#include "CharTypes.h"
#include "SQLExprParser.h"
#include "SQLParserUtils.h"
#include "SQLSelectParser.h"
#include "EOFParserException.h"
#include "Keywords.h"
#include "../../Exception/IllegalArgumentException.h"
#include "../../utils/instanceof.h"
#include "../../utils/FnvHash.h"
#include "../../utils/StringUtils.h"
#include "../../utils/common_ptr.h"
#include "../ast/expr/SQLBooleanExpr.h"
#include "../ast/expr/SQLCaseExpr_Item.h"
#include "../ast/expr/SQLCharExpr.h"
#include "../ast/expr/SQLIdentifierExpr.h"
#include "../ast/expr/SQLDateExpr.h"
#include "../ast/SQLDataType.h"
#include "../ast/SQLOrderingSpecification.h"
#include "../ast/TDDLHint.h"
#include "../ast/statement/SQLUpdateSetItem.h"
#include "../ast/statement/SQLSelectItem.h"
#include "../ast/SQLPartitionValue.h"
#include "../ast/expr/SQLAggregateExpr.h"
#include "../ast/expr/SQLAggregateOption.h"
#include "../../utils/log.h"
#include "../../utils/encode_util.h"
#include "../ast/statement/SQLExternalRecordFormat.h"
#include "../dialect/mysql/parser/MySqlExprParser.h"

SQLParserFeature_list_ptr SQLExprParser::empty_list = std::make_shared<std::list<SQLParserFeature_ptr>>();
std::shared_ptr<std::vector<string_ptr>> SQLExprParser::strings = std::make_shared<std::vector<string_ptr>>(std::vector<string_ptr>{
    make_string_ptr("AVG"),
    make_string_ptr("COUNT"),
    make_string_ptr("MAX"),
    make_string_ptr("MIN"),
    make_string_ptr("STDDEV"),
    make_string_ptr("SUM")});
std::shared_ptr<std::vector<long>> SQLExprParser::AGGREGATE_FUNCTIONS_CODES = FnvHash::fnv1a_64_lower(SQLExprParser::strings, true);
std::shared_ptr<std::vector<string_ptr>> SQLExprParser::AGGREGATE_FUNCTIONS = std::make_shared<std::vector<string_ptr>>();
BOOL_ptr SQLExprParser::__init = SQLExprParser::init();
BOOL_ptr SQLExprParser::init()
{
  for (string_ptr str : *SQLExprParser::strings)
  {
    long hash = FnvHash::fnv1a_64_lower(str);
    // int index = Arrays.binarySearch(AGGREGATE_FUNCTIONS_CODES, hash);

    // int index = std::find(SQLExprParser::AGGREGATE_FUNCTIONS_CODES, SQLExprParser::AGGREGATE_FUNCTIONS_CODES + sizeof(strings) / sizeof(long), hash) - SQLExprParser::AGGREGATE_FUNCTIONS_CODES;
    int index = -1;
    int size = strings->size();
    for (int i = 0; i < size; i++)
    {
      // LOG_INFO << ": i:" << i << ",size:" << size;
      if (SQLExprParser::AGGREGATE_FUNCTIONS_CODES->at(i) == hash)
      {
        index = i;
        break;
      }
    }

    AGGREGATE_FUNCTIONS->push_back(str);
  }
}

// const std::vector<string_ptr > SQLExprParser::AGGREGATE_FUNCTIONS = boost::assign::list_of("AVG")("COUNT")("MAX")("MIN")("STDDEV")("SUM");
// string_ptr []  aggregateFunctions  = AGGREGATE_FUNCTIONS;

SQLExprParser::SQLExprParser(string_ptr theSql)
    : SQLParser(theSql), aggregateFunctions(AGGREGATE_FUNCTIONS)
{
  myHints = std::make_shared<std::list<SQLHint_ptr>>();
  aggregateFunctions = std::make_shared<std::vector<string_ptr>>();
  aggregateFunctionHashCodes = std::make_shared<std::vector<long>>();

  allowIdentifierMethod = BOOL::TRUE;
  // aggregateFunctions  = SQLExprParser::AGGREGATE_FUNCTIONS;
  // LOG_INFO << ", in SQLExprParser::SQLExprParser, constructor 1, theSql is: " << theSql ;;
  // super(sql);
}

SQLExprParser::SQLExprParser(Lexer_ptr theLexer)
    : SQLParser(theLexer), aggregateFunctions(AGGREGATE_FUNCTIONS)
{
  myHints = std::make_shared<std::list<SQLHint_ptr>>();
  aggregateFunctions = std::make_shared<std::vector<string_ptr>>();
  aggregateFunctionHashCodes = std::make_shared<std::vector<long>>();
  allowIdentifierMethod = BOOL::TRUE;
  // LOG_INFO << ", in SQLExprParser::SQLExprParser, constructor 2 " ;;
  // super(lexer);
}

SQLExprParser::SQLExprParser(Lexer_ptr lexer, DbType_ptr dbType)
    : SQLParser(lexer, dbType)
{
  myHints = std::make_shared<std::list<SQLHint_ptr>>();
  aggregateFunctions = std::make_shared<std::vector<string_ptr>>();
  aggregateFunctionHashCodes = std::make_shared<std::vector<long>>();
  allowIdentifierMethod = BOOL::TRUE;
}

SQLExprParser::SQLExprParser(string_ptr sql, DbType_ptr dbType)
    : SQLExprParser(sql, dbType, SQLExprParser::empty_list)
{
  allowIdentifierMethod = BOOL::TRUE;
}

SQLExprParser::SQLExprParser(string_ptr sql, DbType_ptr dbType, SQLParserFeature_list_ptr features)
    : SQLParser(sql, dbType, features)
{
  myHints = std::make_shared<std::list<SQLHint_ptr>>();
  aggregateFunctions = std::make_shared<std::vector<string_ptr>>();
  aggregateFunctionHashCodes = std::make_shared<std::vector<long>>();
  allowIdentifierMethod = BOOL::TRUE;
}

SQLExprParser::~SQLExprParser()
{

  // LOG_INFO << ", in SQLExprParser::~SQLExprParser, destructor step 1" ;;

  // for (std::list<SQLHint_ptr>::iterator it = myHints->begin(); it != myHints->end(); ++it)
  // {
  //   // LOG_INFO << ", in SQLExprParser::~SQLExprParser, destructor step 1.1" ;;
  //   delete *it;
  // }
  // myHints->clear();
}

SQLExpr_ptr SQLExprParser::getExpr()
{
  LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
  if (lexer->token()->name->c_str() == Token::STAR.name->c_str())
  {
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName()->c_str();

    SQLExpr_ptr expr = SQLExpr_ptr(new SQLAllColumnExpr());

    if (lexer->token()->name->c_str() == Token::DOT.name->c_str())
    {
      lexer->nextToken();
      LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
      accept(Token::STAR);
      string_ptr star = make_string_ptr("*");
      return SQLPropertyExpr_ptr(new SQLPropertyExpr(expr, star));
    }
    LOG_INFO << "return";
    return expr;
  }

  LOG_INFO << "goto primary";
  SQLExpr_ptr expr = primary();
  LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
  if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
  {
    LOG_INFO << "return";
    return expr;
  }

  LOG_INFO << "goto exprRest";
  expr = exprRest(expr);
  LOG_INFO << "return";
  return expr;
}

SQLExpr_ptr SQLExprParser::expr() { return getExpr(); }

SQLExpr_ptr SQLExprParser::exprRest(SQLExpr_ptr expr)
{
  expr = bitXorRest(expr);
  expr = multiplicativeRest(expr);
  expr = additiveRest(expr);
  expr = shiftRest(expr);
  expr = bitAndRest(expr);
  expr = bitOrRest(expr);
  expr = inRest(expr);
  expr = relationalRest(expr);
  expr = equalityRest(expr);
  expr = andRest(expr);
  expr = orRest(expr);

  return expr;
}

SQLExpr_ptr SQLExprParser::bitXor()
{
  SQLExpr_ptr expr = primary();
  return bitXorRest(expr);
}

SQLExpr_ptr SQLExprParser::bitXorRest(SQLExpr_ptr expr)
{
  if (lexer->token()->name->c_str() == Token::CARET.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr rightExp = primary();
    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BitwiseXor)), rightExp));
    expr = bitXorRest(expr);
  }

  return expr;
}

SQLExpr_ptr SQLExprParser::multiplicative()
{
  SQLExpr_ptr expr = bitXor();
  return multiplicativeRest(expr);
}

SQLExpr_ptr SQLExprParser::multiplicativeRest(SQLExpr_ptr expr)
{
  if (lexer->token()->name->c_str() == Token::STAR.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr rightExp = bitXor();
    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Multiply)), rightExp));
    expr = multiplicativeRest(expr);
  }
  else if (lexer->token()->name->c_str() == Token::SLASH.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr rightExp = bitXor();
    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Divide)), rightExp));
    expr = multiplicativeRest(expr);
  }
  else if (lexer->token()->name->c_str() == Token::PERCENT.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr rightExp = bitXor();
    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Modulus)), rightExp));
    expr = multiplicativeRest(expr);
  }
  return expr;
}

SQLExpr_ptr SQLExprParser::primary()
{
  LOG_INFO << "in primary";
  wstring_list_ptr beforeComments = std::make_shared<std::list<wstring_ptr>>();
  if (lexer->isKeepComments() && lexer->hasComment())
  {
    LOG_INFO;
    beforeComments = lexer->readAndResetComments();
  }

  SQLExpr_ptr sqlExpr = NULL;

  Token_ptr tok = lexer->token();
  LOG_INFO << "token name:" << tok->getName()->c_str() << ",stringVal_:" << encode_util::UnicodeToUTF8(lexer->stringVal_).c_str();
  if (tok->name->c_str() == Token::LPAREN.name->c_str())
  {
    int paranCount = 0;
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
    if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
    {
      lexer->nextToken();
      LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
      sqlExpr = SQLMethodInvokeExpr_ptr(new SQLMethodInvokeExpr());
      goto out;
    }

    sqlExpr = getExpr();

    LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      SQLListExpr_ptr listExpr = SQLListExpr_ptr(new SQLListExpr());
      listExpr->addItem(sqlExpr);
      do
      {
        lexer->nextToken();
        LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
        listExpr->addItem(getExpr());
      } while (lexer->token()->name->c_str() == Token::COMMA.name->c_str());

      sqlExpr = listExpr;
    }

    if (instanceof <SQLExpr, SQLBinaryOpExpr>(sqlExpr))
    {
      (std::dynamic_pointer_cast<SQLBinaryOpExpr>(sqlExpr))->setParenthesized(BOOL::TRUE);
    }

    if ((lexer->token()->name->c_str() == Token::UNION.name->c_str() ||
         lexer->token()->name->c_str() == Token::MINUS.name->c_str() ||
         lexer->token()->name->c_str() == Token::EXCEPT.name->c_str()) &&
        instanceof <SQLExpr, SQLQueryExpr>(sqlExpr))
    {
      SQLQueryExpr_ptr queryExpr = std::dynamic_pointer_cast<SQLQueryExpr>(sqlExpr);

      SQLSelectQuery_ptr query = this->createSelectParser()->queryRest(queryExpr->getSubQuery()->getQuery(), BOOL::TRUE);
      queryExpr->getSubQuery()->setQuery(query);
    }

    accept(Token::RPAREN);
  }
  else if (tok->name->c_str() == Token::INSERT.name->c_str())
  {
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
    if (lexer->token()->name->c_str() != Token::LPAREN.name->c_str())
    {
      std::string tmp = "syntax error. ";
      tmp += encode_util::UnicodeToUTF8(lexer->info());
      throw new ParserException(make_string_ptr(tmp));
    }
    string_ptr tmp = make_string_ptr("INSERT");
    SQLIdentifierExpr_ptr sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
  }
  else if (tok->name->c_str() == Token::IDENTIFIER.name->c_str())
  {
    LOG_INFO << "pos:" << lexer->pos();
    std::string ident_tmp = encode_util::UnicodeToUTF8(*lexer->stringVal());
    string_ptr ident = make_string_ptr(ident_tmp);
    long hash_lower = lexer->hashLCase();
    LOG_INFO << "ident:" << ident << ",hash_lower:" << hash_lower;
    LOG_INFO << "pos:" << lexer->pos();

    int sourceLine = -1, sourceColumn = -1;
    LOG_INFO << "lexer->keepSourceLocation:" << lexer->keepSourceLocation;
    if (lexer->keepSourceLocation)
    {
      LOG_INFO << "lexer->keepSourceLocation is BOOL::TRUE";
      lexer->computeRowAndColumn();
      LOG_INFO << "pos:" << lexer->pos();
      sourceLine = lexer->posLine;
      sourceColumn = lexer->posColumn;
    }

    LOG_INFO << "goto nextToken";
    LOG_INFO << "pos:" << lexer->pos();
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
    LOG_INFO << "hash_lower:" << hash_lower;

    if (hash_lower == FnvHash::Constants::TRY_CAST)
    {
      accept(Token::LPAREN);
      SQLCastExpr_ptr cast = SQLCastExpr_ptr(new SQLCastExpr());
      cast->setTry(BOOL::TRUE);
      cast->setExpr(getExpr());
      accept(Token::AS);
      cast->setDataType(parseDataType(BOOL::FALSE));
      accept(Token::RPAREN);

      sqlExpr = cast;
    }
    else if (hash_lower == FnvHash::Constants::DATE &&
             (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
              lexer->token()->name->c_str() == Token::VARIANT.name->c_str()) &&
             (SQLDateExpr::isSupport(dbType)))
    {
      //   string_ptr  literal = lexer->token()->name->c_str() == Token::LITERAL_CHARS ? lexer->stringVal() : "?";
      //   lexer->nextToken();
      //   SQLDateExpr *dateExpr = new SQLDateExpr();
      //   dateExpr.setLiteral(literal);
      //   sqlExpr = dateExpr;
    }
    else if (hash_lower == FnvHash::Constants::TIMESTAMP &&
             (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
              lexer->token()->name->c_str() == Token::VARIANT.name->c_str()) &&
             DbType::oracle.name->c_str() != dbType->name->c_str())
    {
      //   SQLTimestampExpr* dateExpr = new SQLTimestampExpr(lexer->stringVal());
      //   lexer->nextToken();
      //   sqlExpr = dateExpr;
    }
    else if (hash_lower == FnvHash::Constants::TIME &&
             (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
              lexer->token()->name->c_str() == Token::VARIANT.name->c_str()))
    {
      //   SQLTimeExpr dateExpr = new SQLTimeExpr(lexer->stringVal());
      //   lexer->nextToken();
      //   sqlExpr = dateExpr;
    }
    else if (hash_lower == FnvHash::Constants::TIME &&
             lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      //   SQLTimeExpr dateExpr = new SQLTimeExpr(SQLUtils::normalize(lexer->stringVal()));
      //   lexer->nextToken();
      //   sqlExpr = dateExpr;
    }
    else if (hash_lower == FnvHash::Constants::DATETIME &&
             (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
              lexer->token()->name->c_str() == Token::VARIANT.name->c_str()))
    {
      //   SQLDateTimeExpr dateExpr = new SQLDateTimeExpr(lexer->stringVal());
      //   lexer->nextToken();
      //   sqlExpr = dateExpr;
    }
    else if (hash_lower == FnvHash::Constants::DATETIME &&
             lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      //   SQLDateTimeExpr dateExpr = new SQLDateTimeExpr(SQLUtils::normalize(lexer->stringVal()));
      //   lexer->nextToken();
      //   sqlExpr = dateExpr;
    }
    else if (hash_lower == FnvHash::Constants::BOOLEAN &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   sqlExpr = new SQLBooleanExpr(Boolean.valueOf(lexer->stringVal()));
      //   lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::VARCHAR &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   if (dbType == DbType::mysql)
      //   {
      //     MySqlCharExpr *mysqlChar = new MySqlCharExpr(lexer->stringVal());
      //     mysqlChar.setType("VARCHAR");
      //     sqlExpr = mysqlChar;
      //   }
      //   else
      //   {
      //     sqlExpr = new SQLCharExpr(lexer->stringVal());
      //   }
      //   lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::CHAR &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   if (dbType == DbType::mysql)
      //   {
      //     MySqlCharExpr *mysqlChar = new MySqlCharExpr(lexer->stringVal());
      //     mysqlChar.setType("CHAR");
      //     sqlExpr = mysqlChar;
      //   }
      //   else
      //   {
      //     sqlExpr = new SQLCharExpr(lexer->stringVal());
      //   }
      //   lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             StringUtils::startWith(ident, make_string_ptr("0x")) &&
             (ident->length() % 2) == 0)
    {
      //   sqlExpr = new SQLHexExpr(ident->substring(2));
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             hash_lower == FnvHash::Constants::JSON &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   sqlExpr = new SQLJSONExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             hash_lower == FnvHash::Constants::DECIMAL &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   sqlExpr = new SQLDecimalExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             hash_lower == FnvHash::Constants::DOUBLE &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   sqlExpr = new SQLDoubleExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             hash_lower == FnvHash::Constants::FLOAT &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   sqlExpr = new SQLFloatExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             hash_lower == FnvHash::Constants::SMALLINT &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   sqlExpr = new SQLSmallIntExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             hash_lower == FnvHash::Constants::TINYINT &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   sqlExpr = new SQLTinyIntExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             hash_lower == FnvHash::Constants::BIGINT &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   string_ptr  strVal = lexer->stringVal();
      //   if (strVal.startsWith("--"))
      //   {
      //     strVal = strVal.substring(2);
      //   }
      //   sqlExpr = new SQLBigIntExpr(strVal);
      //   lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             hash_lower == FnvHash::Constants::INTEGER &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   string_ptr  strVal = lexer->stringVal();
      //   if (strVal.startsWith("--"))
      //   {
      //     strVal = strVal.substring(2);
      //   }
      //   SQLIntegerExpr integerExpr = SQLIntegerExpr.ofIntOrLong(Long.parseLong(strVal));
      //   integerExpr.setType("INTEGER");
      //   sqlExpr = integerExpr;
      //   lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             hash_lower == FnvHash::Constants::REAL &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      //   sqlExpr = new SQLRealExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::DATE &&
             lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      //   sqlExpr = new SQLDateExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::DATETIME &&
             lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      //   sqlExpr = new SQLDateTimeExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::TIMESTAMP &&
             lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      //   sqlExpr = new SQLTimestampExpr(lexer->stringVal());
      //   lexer->nextToken();
    }
    else
    {
      char c0 = ident->at(0);
      LOG_INFO << "c0:" << c0;
      if (c0 == '`' || c0 == '[' || c0 == '"')
      {
        if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))))
        {
          ident = make_string_ptr(ident->substr(1, ident->length() - 2));
        }
        hash_lower = FnvHash::hashCode64(ident);
      }
      LOG_INFO << "ident:" << ident->c_str() << ",hash_lower:" << hash_lower;
      SQLIdentifierExpr_ptr identifierExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(ident, hash_lower));
      LOG_INFO << "sourceLine:" << sourceLine;
      LOG_INFO << "sourceColumn:" << sourceColumn;
      if (sourceLine != -1)
      {
        identifierExpr->setSourceLine(sourceLine);
        identifierExpr->setSourceColumn(sourceColumn);
      }
      sqlExpr = identifierExpr;
    }
  }
  else if (tok->name->c_str() == Token::NEW.name->c_str())
  {
    std::string tmp = "TODO ";
    tmp += encode_util::UnicodeToUTF8(lexer->info());
    throw new ParserException(make_string_ptr(tmp));
  }
  else if (tok->name->c_str() == Token::LITERAL_INT.name->c_str())
  {

    int number = lexer->integerValue();
    lexer->nextToken();

    if (lexer->identifierEquals(FnvHash::Constants::BD))
    {
      // SQLDecimalExpr *decimalExpr = new SQLDecimalExpr();
      // decimalExpr.setValue(new BigDecimal(number.intValue()));
      // lexer->nextToken();
      // sqlExpr = decimalExpr;
    }
    else
    {
      sqlExpr = SQLIntegerExpr_ptr(new SQLIntegerExpr(number));
    }
  }
  else if (tok->name->c_str() == Token::LITERAL_FLOAT.name->c_str())
  {

    sqlExpr = SQLNumberExpr_ptr(lexer->numberExpr());
    lexer->nextToken();

    if (lexer->identifierEquals(FnvHash::Constants::BD))
    {
      // SQLDecimalExpr *decimalExpr = new SQLDecimalExpr();
      // decimalExpr.setValue(new BigDecimal(sqlExpr.toString()));
      // lexer->nextToken();
      // sqlExpr = decimalExpr;
    }
  }
  else if (tok->name->c_str() == Token::LITERAL_CHARS.name->c_str())
  {
    string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    LOG_INFO << "tmp:" << tmp->c_str();
    sqlExpr = SQLCharExpr_ptr(new SQLCharExpr(tmp));

    if (DbType::mysql.name->c_str() == dbType->name->c_str())
    {
      lexer->nextTokenValue();

      for (;;)
      {
        if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
        {
          string_ptr concat = (std::dynamic_pointer_cast<SQLCharExpr>(sqlExpr))->getText();
          concat->append(encode_util::UnicodeToUTF8(*lexer->stringVal()));
          lexer->nextTokenValue();
          sqlExpr = SQLCharExpr_ptr(new SQLCharExpr(concat));
        }
        else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
                 lexer->token()->name->c_str() == Token::LITERAL_NCHARS.name->c_str())
        {
          string_ptr concat = (std::dynamic_pointer_cast<SQLCharExpr>(sqlExpr))->getText();
          concat->append(encode_util::UnicodeToUTF8(*lexer->stringVal()));
          lexer->nextTokenValue();
          sqlExpr = SQLCharExpr_ptr(new SQLCharExpr(concat));
        }
        else
        {
          break;
        }
      }
    }
    else
    {
      lexer->nextToken();
    }
  }
  else if (tok->name->c_str() == Token::LITERAL_NCHARS.name->c_str())
  {
    string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    sqlExpr = SQLNCharExpr_ptr(new SQLNCharExpr(tmp));
    lexer->nextToken();

    if (DbType::mysql.name->c_str() == dbType->name->c_str())
    {
      SQLMethodInvokeExpr_ptr concat = NULL;
      for (;;)
      {
        if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
        {
          if (concat == NULL)
          {
            string_ptr tmp = make_string_ptr("CONCAT");
            concat = SQLMethodInvokeExpr_ptr(new SQLMethodInvokeExpr(tmp));
            concat->addArgument(sqlExpr);
            sqlExpr = concat;
          }
          string_ptr alias_ = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
          lexer->nextToken();
          string_ptr tmp = make_string_ptr(alias_->substr(1, alias_->length() - 2));
          SQLCharExpr_ptr concat_right = SQLCharExpr_ptr(new SQLCharExpr(tmp));
          concat->addArgument(concat_right);
        }
        else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
                 lexer->token()->name->c_str() == Token::LITERAL_NCHARS.name->c_str())
        {
          if (concat == NULL)
          {
            string_ptr tmp = make_string_ptr("CONCAT");
            concat = SQLMethodInvokeExpr_ptr(new SQLMethodInvokeExpr(tmp));
            concat->addArgument(sqlExpr);
            sqlExpr = concat;
          }

          string_ptr chars = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
          lexer->nextToken();
          SQLCharExpr_ptr concat_right = SQLCharExpr_ptr(new SQLCharExpr(chars));
          concat->addArgument(concat_right);
        }
        else
        {
          break;
        }
      }
    }
  }
  else if (tok->name->c_str() == Token::VARIANT.name->c_str())
  {

    string_ptr varName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    LOG_INFO << "varName:" << varName->c_str();
    lexer->nextToken();

    if (*varName == ":" &&
        lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() &&
        DbType::oracle.name->c_str() == dbType->name->c_str())
    {
      string_ptr part2 = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      varName->append(*part2);
    }

    SQLVariantRefExpr_ptr varRefExpr = SQLVariantRefExpr_ptr(new SQLVariantRefExpr(varName));
    if (StringUtils::startWith(varName, make_string_ptr(":")))
    {
      varRefExpr->setIndex(lexer->nextVarIndex());
    }
    if ((*varRefExpr->getName() == "@") &&
        (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
         (lexer->token()->name->c_str() == Token::VARIANT.name->c_str() &&
          StringUtils::startWith(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())), make_string_ptr("@")))))
    {
      string_ptr tmp = make_string_ptr("@'" + encode_util::UnicodeToUTF8(*lexer->stringVal()) + "'");
      varRefExpr->setName(tmp);
      lexer->nextToken();
    }
    else if (*varRefExpr->getName() == "@@" &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      string_ptr tmp = make_string_ptr("@@'" + encode_util::UnicodeToUTF8(*lexer->stringVal()) + "'");
      varRefExpr->setName(tmp);
      lexer->nextToken();
    }
    sqlExpr = varRefExpr;
  }
  else if (tok->name->c_str() == Token::DEFAULT.name->c_str())
  {

    if (dbType->name->c_str() == DbType::clickhouse.name->c_str())
    {
      string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    }
    else
    {
      sqlExpr = SQLDefaultExpr_ptr(new SQLDefaultExpr());
    }
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::DUAL.name->c_str() ||
           tok->name->c_str() == Token::KEY.name->c_str() ||
           tok->name->c_str() == Token::LIMIT.name->c_str() ||
           tok->name->c_str() == Token::SCHEMA.name->c_str() ||
           tok->name->c_str() == Token::COLUMN.name->c_str() ||
           tok->name->c_str() == Token::IF.name->c_str() ||
           tok->name->c_str() == Token::END.name->c_str() ||
           tok->name->c_str() == Token::COMMENT.name->c_str() ||
           tok->name->c_str() == Token::COMPUTE.name->c_str() ||
           tok->name->c_str() == Token::ENABLE.name->c_str() ||
           tok->name->c_str() == Token::DISABLE.name->c_str() ||
           tok->name->c_str() == Token::INITIALLY.name->c_str() ||
           tok->name->c_str() == Token::SEQUENCE.name->c_str() ||
           tok->name->c_str() == Token::USER.name->c_str() ||
           tok->name->c_str() == Token::EXPLAIN.name->c_str() ||
           tok->name->c_str() == Token::WITH.name->c_str() ||
           tok->name->c_str() == Token::GRANT.name->c_str() ||
           tok->name->c_str() == Token::REPLACE.name->c_str() ||
           tok->name->c_str() == Token::INDEX.name->c_str() ||
           tok->name->c_str() == Token::PCTFREE.name->c_str() ||
           tok->name->c_str() == Token::INITRANS.name->c_str() ||
           tok->name->c_str() == Token::MAXTRANS.name->c_str() ||
           tok->name->c_str() == Token::SEGMENT.name->c_str() ||
           tok->name->c_str() == Token::CREATION.name->c_str() ||
           tok->name->c_str() == Token::IMMEDIATE.name->c_str() ||
           tok->name->c_str() == Token::DEFERRED.name->c_str() ||
           tok->name->c_str() == Token::STORAGE.name->c_str() ||
           tok->name->c_str() == Token::NEXT.name->c_str() ||
           tok->name->c_str() == Token::MINEXTENTS.name->c_str() ||
           tok->name->c_str() == Token::MAXEXTENTS.name->c_str() ||
           tok->name->c_str() == Token::MAXSIZE.name->c_str() ||
           tok->name->c_str() == Token::PCTINCREASE.name->c_str() ||
           tok->name->c_str() == Token::FLASH_CACHE.name->c_str() ||
           tok->name->c_str() == Token::CELL_FLASH_CACHE.name->c_str() ||
           tok->name->c_str() == Token::NONE.name->c_str() ||
           tok->name->c_str() == Token::LOB.name->c_str() ||
           tok->name->c_str() == Token::STORE.name->c_str() ||
           tok->name->c_str() == Token::ROW.name->c_str() ||
           tok->name->c_str() == Token::CHUNK.name->c_str() ||
           tok->name->c_str() == Token::CACHE.name->c_str() ||
           tok->name->c_str() == Token::NOCACHE.name->c_str() ||
           tok->name->c_str() == Token::LOGGING.name->c_str() ||
           tok->name->c_str() == Token::NOCOMPRESS.name->c_str() ||
           tok->name->c_str() == Token::KEEP_DUPLICATES.name->c_str() ||
           tok->name->c_str() == Token::EXCEPTIONS.name->c_str() ||
           tok->name->c_str() == Token::PURGE.name->c_str() ||
           tok->name->c_str() == Token::FULL.name->c_str() ||
           tok->name->c_str() == Token::TO.name->c_str() ||
           tok->name->c_str() == Token::IDENTIFIED.name->c_str() ||
           tok->name->c_str() == Token::PASSWORD.name->c_str() ||
           tok->name->c_str() == Token::BINARY.name->c_str() ||
           tok->name->c_str() == Token::WINDOW.name->c_str() ||
           tok->name->c_str() == Token::OFFSET.name->c_str() ||
           tok->name->c_str() == Token::SHARE.name->c_str() ||
           tok->name->c_str() == Token::START.name->c_str() ||
           tok->name->c_str() == Token::CONNECT.name->c_str() ||
           tok->name->c_str() == Token::MATCHED.name->c_str() ||
           tok->name->c_str() == Token::ERRORS.name->c_str() ||
           tok->name->c_str() == Token::REJECT.name->c_str() ||
           tok->name->c_str() == Token::UNLIMITED.name->c_str() ||
           tok->name->c_str() == Token::BEGIN.name->c_str() ||
           tok->name->c_str() == Token::EXCLUSIVE.name->c_str() ||
           tok->name->c_str() == Token::MODE.name->c_str() ||
           tok->name->c_str() == Token::ADVISE.name->c_str() ||
           tok->name->c_str() == Token::VIEW.name->c_str() ||
           tok->name->c_str() == Token::ESCAPE.name->c_str() ||
           tok->name->c_str() == Token::OVER.name->c_str() ||
           tok->name->c_str() == Token::ORDER.name->c_str() ||
           tok->name->c_str() == Token::CONSTRAINT.name->c_str() ||
           tok->name->c_str() == Token::TYPE.name->c_str() ||
           tok->name->c_str() == Token::OPEN.name->c_str() ||
           tok->name->c_str() == Token::REPEAT.name->c_str() ||
           tok->name->c_str() == Token::TABLE.name->c_str() ||
           tok->name->c_str() == Token::TRUNCATE.name->c_str() ||
           tok->name->c_str() == Token::EXCEPTION.name->c_str() ||
           tok->name->c_str() == Token::FUNCTION.name->c_str() ||
           tok->name->c_str() == Token::IDENTITY.name->c_str() ||
           tok->name->c_str() == Token::EXTRACT.name->c_str() ||
           tok->name->c_str() == Token::DESC.name->c_str() ||
           tok->name->c_str() == Token::DO.name->c_str() ||
           tok->name->c_str() == Token::GROUP.name->c_str() ||
           tok->name->c_str() == Token::MOD.name->c_str() ||
           tok->name->c_str() == Token::CONCAT.name->c_str() ||
           tok->name->c_str() == Token::PRIMARY.name->c_str() ||
           tok->name->c_str() == Token::PARTITION.name->c_str() ||
           tok->name->c_str() == Token::LEAVE.name->c_str() ||
           tok->name->c_str() == Token::CLOSE.name->c_str() ||
           tok->name->c_str() == Token::CONDITION.name->c_str() ||
           tok->name->c_str() == Token::OUT.name->c_str() ||
           tok->name->c_str() == Token::USE.name->c_str() ||
           tok->name->c_str() == Token::EXCEPT.name->c_str() ||
           tok->name->c_str() == Token::INTERSECT.name->c_str() ||
           tok->name->c_str() == Token::MERGE.name->c_str() ||
           tok->name->c_str() == Token::MINUS.name->c_str() ||
           tok->name->c_str() == Token::UNTIL.name->c_str() ||
           tok->name->c_str() == Token::TOP.name->c_str() ||
           tok->name->c_str() == Token::SHOW.name->c_str() ||
           tok->name->c_str() == Token::INOUT.name->c_str() ||
           tok->name->c_str() == Token::OUTER.name->c_str() ||
           tok->name->c_str() == Token::QUALIFY.name->c_str())
  {
    string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::CASE.name->c_str())
  {

    SQLCaseExpr_ptr caseExpr = SQLCaseExpr_ptr(new SQLCaseExpr());
    lexer->nextToken();
    if (lexer->token()->name->c_str() != Token::WHEN.name->c_str())
    {
      caseExpr->setValueExpr(getExpr());
    }

    accept(Token::WHEN);
    SQLExpr_ptr testExpr = getExpr();
    accept(Token::THEN);
    SQLExpr_ptr valueExpr = getExpr();
    SQLCaseExpr_Item_ptr caseItem = SQLCaseExpr_Item_ptr(new SQLCaseExpr_Item(testExpr, valueExpr));
    caseExpr->addItem(caseItem);

    while (lexer->token()->name->c_str() == Token::WHEN.name->c_str())
    {
      lexer->nextToken();
      testExpr = getExpr();
      accept(Token::THEN);
      valueExpr = getExpr();
      caseItem = SQLCaseExpr_Item_ptr(new SQLCaseExpr_Item(testExpr, valueExpr));
      caseExpr->addItem(caseItem);
    }

    if (lexer->token()->name->c_str() == Token::ELSE.name->c_str())
    {
      lexer->nextToken();
      caseExpr->setElseExpr(getExpr());
    }

    accept(Token::END);

    sqlExpr = caseExpr;
  }
  else if (tok->name->c_str() == Token::EXISTS.name->c_str())
  {

    string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str() ||
        lexer->token()->name->c_str() == Token::DOT.name->c_str())
    {
      sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(strVal));
    }
    else
    {
      accept(Token::LPAREN);
      sqlExpr = SQLExistsExpr_ptr(new SQLExistsExpr(createSelectParser()->select()));
      accept(Token::RPAREN);
      parseQueryPlanHint(sqlExpr);
    }
  }
  else if (tok->name->c_str() == Token::NOT.name->c_str())
  {

    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EXISTS.name->c_str())
    {
      lexer->nextToken();
      accept(Token::LPAREN);
      SQLExistsExpr_ptr exists = SQLExistsExpr_ptr(new SQLExistsExpr(createSelectParser()->select(), BOOL::TRUE));
      accept(Token::RPAREN);

      parseQueryPlanHint(exists);
      if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
      {
        exists->setNot(BOOL::FALSE);
        SQLExpr_ptr relational = this->relationalRest(exists);
        sqlExpr = SQLNotExpr_ptr(new SQLNotExpr(relational));
      }
      else
      {
        sqlExpr = exists;
      }
    }
    else if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();

      SQLExpr_ptr notTarget = getExpr();

      accept(Token::RPAREN);
      notTarget = bitXorRest(notTarget);
      notTarget = multiplicativeRest(notTarget);
      notTarget = additiveRest(notTarget);
      notTarget = shiftRest(notTarget);
      notTarget = bitAndRest(notTarget);
      notTarget = bitOrRest(notTarget);
      notTarget = inRest(notTarget);
      notTarget = relationalRest(notTarget);
      sqlExpr = SQLNotExpr_ptr(new SQLNotExpr(notTarget));

      parseQueryPlanHint(sqlExpr);
      return primaryRest(sqlExpr);
    }
    else
    {
      SQLExpr_ptr restExpr = relational();
      sqlExpr = SQLNotExpr_ptr(new SQLNotExpr(restExpr));
      parseQueryPlanHint(sqlExpr);
    }
  }
  else if (tok->name->c_str() == Token::FROM.name->c_str() ||
           tok->name->c_str() == Token::SELECT.name->c_str())
  {

    SQLQueryExpr_ptr queryExpr = SQLQueryExpr_ptr(new SQLQueryExpr(createSelectParser()->select()));
    sqlExpr = queryExpr;
  }
  else if (tok->name->c_str() == Token::CAST.name->c_str())
  {

    string_ptr castStr = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();

    if (lexer->token()->name->c_str() != Token::LPAREN.name->c_str())
    {
      sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(castStr));
    }
    else
    {
      lexer->nextToken();
      SQLCastExpr_ptr cast = SQLCastExpr_ptr(new SQLCastExpr());
      cast->setExpr(getExpr());
      accept(Token::AS);
      cast->setDataType(parseDataType(BOOL::FALSE));
      accept(Token::RPAREN);

      sqlExpr = cast;
    }
  }
  else if (tok->name->c_str() == Token::SUB.name->c_str())
  {

    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str())
    {
      long integerValue = lexer->integerValue();
      // if (integerValue instanceof Integer)
      // {
      //   int intVal = integerValue.intValue();
      //   if (intVal == Integer.MIN_VALUE)
      //   {
      //     integerValue = Long.valueOf(((long)intVal) * -1);
      //   }
      //   else
      //   {
      //     integerValue = Integer.valueOf(intVal * -1);
      //   }
      // }
      // else if (integerValue instanceof Long)
      // {
      long longVal = integerValue;
      // if (longVal == 2147483648L)
      // {
      //   integerValue = Integer.valueOf((int)(((long)longVal) * -1));
      // }
      // else
      // {
      integerValue = longVal * -1;
      // }
      // }
      // else
      // {
      //   integerValue = ((BigInteger)integerValue).negate();
      // }
      sqlExpr = SQLIntegerExpr_ptr(new SQLIntegerExpr(integerValue));
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::LITERAL_FLOAT.name->c_str())
    {
      sqlExpr = SQLNumberExpr_ptr(lexer->numberExpr(BOOL::TRUE));
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
             lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      if (dbType->name->c_str() == DbType::mysql.name->c_str())
      {
        string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        sqlExpr = SQLCharExpr_ptr(new SQLCharExpr(tmp));
      }
      else
      {
        string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
      }
      lexer->nextToken();

      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str() ||
          lexer->token()->name->c_str() == Token::LBRACKET.name->c_str() ||
          lexer->token()->name->c_str() == Token::DOT.name->c_str())
      {
        sqlExpr = primaryRest(sqlExpr);
      }
      sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Negative)), sqlExpr));
    }
    else if (lexer->token()->name->c_str() == Token::QUES.name->c_str())
    {
      SQLVariantRefExpr *variantRefExpr = new SQLVariantRefExpr("?");
      variantRefExpr->setIndex(lexer->nextVarIndex());
      sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Negative)), SQLVariantRefExpr_ptr(variantRefExpr)));
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::PLUS.name->c_str() ||
             lexer->token()->name->c_str() == Token::SUB.name->c_str() ||
             lexer->token()->name->c_str() == Token::LPAREN.name->c_str() ||
             lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() ||
             lexer->token()->name->c_str() == Token::BANG.name->c_str() ||
             lexer->token()->name->c_str() == Token::CASE.name->c_str() ||
             lexer->token()->name->c_str() == Token::CAST.name->c_str() ||
             lexer->token()->name->c_str() == Token::XNULL.name->c_str() ||
             lexer->token()->name->c_str() == Token::INTERVAL.name->c_str() ||
             lexer->token()->name->c_str() == Token::LBRACE.name->c_str() ||
             lexer->token()->name->c_str() == Token::IF.name->c_str() ||
             lexer->token()->name->c_str() == Token::CHECK.name->c_str() ||
             lexer->token()->name->c_str() == Token::INDEX.name->c_str() ||
             lexer->token()->name->c_str() == Token::PRIMARY.name->c_str() ||
             lexer->token()->name->c_str() == Token::KEY.name->c_str() ||
             lexer->token()->name->c_str() == Token::REPLACE.name->c_str())
    {
      sqlExpr = primary();

      while (lexer->token()->name->c_str() == Token::HINT.name->c_str())
      {
        lexer->nextToken();
      }

      sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Negative)), sqlExpr));
    }
    else if (lexer->token()->name->c_str() == Token::VARIANT.name->c_str())
    {
      sqlExpr = primary();
      sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Negative)), sqlExpr));
    }
    else
    {
      throw new ParserException(make_string_ptr("TODO : " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }
  else if (tok->name->c_str() == Token::PLUS.name->c_str())
  {

    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
        lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
      sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Plus)), sqlExpr));
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::QUES.name->c_str())
    {
      SQLVariantRefExpr *variantRefExpr = new SQLVariantRefExpr("?");
      variantRefExpr->setIndex(lexer->nextVarIndex());
      sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Plus)), SQLVariantRefExpr_ptr(variantRefExpr)));
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::PLUS.name->c_str() ||
             lexer->token()->name->c_str() == Token::SUB.name->c_str() ||
             lexer->token()->name->c_str() == Token::LITERAL_FLOAT.name->c_str() ||
             lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str() ||
             lexer->token()->name->c_str() == Token::LPAREN.name->c_str() ||
             lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() ||
             lexer->token()->name->c_str() == Token::BANG.name->c_str() ||
             lexer->token()->name->c_str() == Token::CASE.name->c_str() ||
             lexer->token()->name->c_str() == Token::CAST.name->c_str() ||
             lexer->token()->name->c_str() == Token::XNULL.name->c_str() ||
             lexer->token()->name->c_str() == Token::INTERVAL.name->c_str() ||
             lexer->token()->name->c_str() == Token::LBRACE.name->c_str() ||
             lexer->token()->name->c_str() == Token::IF.name->c_str() ||
             lexer->token()->name->c_str() == Token::CHECK.name->c_str() ||
             lexer->token()->name->c_str() == Token::REPLACE.name->c_str())
    {
      sqlExpr = primary();

      while (lexer->token()->name->c_str() == Token::HINT.name->c_str())
      {
        lexer->nextToken();
      }

      sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Plus)), sqlExpr));
    }
    else
    {
      std::string tmp = "TODO ";
      tmp += encode_util::UnicodeToUTF8(lexer->info());
      throw new ParserException(make_string_ptr(tmp));
    }
  }
  else if (tok->name->c_str() == Token::TILDE.name->c_str())
  {

    lexer->nextToken();
    SQLExpr_ptr unaryValueExpr = primary();
    SQLUnaryExpr_ptr unary = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Compl)), unaryValueExpr));
    sqlExpr = unary;
  }
  else if (tok->name->c_str() == Token::QUES.name->c_str())
  {

    if (dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      lexer->nextTokenValue();
    }
    else
    {
      lexer->nextToken();
    }
    SQLVariantRefExpr_ptr quesVarRefExpr = SQLVariantRefExpr_ptr(new SQLVariantRefExpr("?"));
    quesVarRefExpr->setIndex(lexer->nextVarIndex());
    sqlExpr = quesVarRefExpr;
  }
  else if (tok->name->c_str() == Token::LEFT.name->c_str())
  {
    string_ptr tmp = make_string_ptr("LEFT");
    sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::RIGHT.name->c_str())
  {
    string_ptr tmp = make_string_ptr("RIGHT");
    sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::INNER.name->c_str())
  {
    string_ptr tmp = make_string_ptr("INNER");
    sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::DATABASE.name->c_str())
  {
    string_ptr tmp = make_string_ptr("DATABASE");
    sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::CASCADE.name->c_str())
  {
    string_ptr tmp = make_string_ptr("CASCADE");
    sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::LOCK.name->c_str())
  {
    string_ptr tmp = make_string_ptr("LOCK");
    sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::XNULL.name->c_str())
  {

    sqlExpr = SQLNullExpr_ptr(new SQLNullExpr());
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::BANG.name->c_str())
  {

    lexer->nextToken();
    sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Not)), primary()));
  }
  else if (tok->name->c_str() == Token::BANGBANG.name->c_str())
  {

    if (dbType->name->c_str() == DbType::hive.name->c_str())
    {
      throw new ParserException(make_string_ptr(encode_util::UnicodeToUTF8(lexer->info())));
    }
    lexer->nextToken();
    sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Not)), primary()));
  }
  else if (tok->name->c_str() == Token::BANG_TILDE.name->c_str())
  {

    lexer->nextToken();
    SQLExpr_ptr bangExpr = primary();
    sqlExpr = SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Not)), SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Compl)), bangExpr))));
  }
  else if (tok->name->c_str() == Token::LITERAL_HEX.name->c_str())
  {

    string_ptr hex = make_string_ptr(encode_util::UnicodeToUTF8(lexer->hexString()));
    sqlExpr = SQLHexExpr_ptr(new SQLHexExpr(hex));
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::INTERVAL.name->c_str())
  {

    sqlExpr = parseInterval();
  }
  else if (tok->name->c_str() == Token::COLON.name->c_str())
  {

    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      string_ptr tmp;
      tmp->append(":\"");
      tmp->append(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      tmp->append("\"");
      sqlExpr = SQLVariantRefExpr_ptr(new SQLVariantRefExpr(tmp));
      lexer->nextToken();
    }
  }
  else if (tok->name->c_str() == Token::ANY.name->c_str())
  {

    sqlExpr = parseAny();
  }
  else if (tok->name->c_str() == Token::SOME.name->c_str())
  {

    sqlExpr = parseSome();
  }
  else if (tok->name->c_str() == Token::ALL.name->c_str())
  {

    sqlExpr = parseAll();
  }
  else if (tok->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
  {

    sqlExpr = parseAliasExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
    lexer->nextToken();
  }
  else if (tok->name->c_str() == Token::XEOF.name->c_str())
  {

    throw new EOFParserException();
  }
  else if (tok->name->c_str() == Token::XTRUE.name->c_str())
  {

    lexer->nextToken();
    sqlExpr = SQLBooleanExpr_ptr(new SQLBooleanExpr(true));
  }
  else if (tok->name->c_str() == Token::XFALSE.name->c_str())
  {

    lexer->nextToken();
    sqlExpr = SQLBooleanExpr_ptr(new SQLBooleanExpr(false));
  }
  else if (tok->name->c_str() == Token::BITS.name->c_str())
  {

    string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
    // sqlExpr = new SQLBinaryExpr(strVal);
  }
  else if (tok->name->c_str() == Token::GLOBAL.name->c_str() ||
           tok->name->c_str() == Token::CONTAINS.name->c_str())
  {

    sqlExpr = inRest(NULL);
  }
  else if (tok->name->c_str() == Token::SET.name->c_str())
  {

    Lexer_SavePoint_ptr savePoint = lexer->mark();
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::SET.name->c_str() &&
        dbType->name->c_str() == DbType::odps.name->c_str())
    {
      lexer->nextToken();
    }
    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      string_ptr tmp = make_string_ptr("SET");
      sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    }
    else if (lexer->token()->name->c_str() == Token::DOT.name->c_str())
    {
      string_ptr tmp = make_string_ptr("SET");
      sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
      sqlExpr = this->primaryRest(sqlExpr);
    }
    else
    {
      lexer->reset(savePoint);
      throw new ParserException(make_string_ptr("ERROR. " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }
  else if (tok->name->c_str() == Token::LBRACE.name->c_str())
  {

    lexer->nextToken();
    if (lexer->identifierEquals(FnvHash::Constants::TS))
    {
      lexer->nextToken();
      string_ptr literal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      // sqlExpr = new SQLTimestampExpr(literal);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::D) ||
             lexer->identifierEquals(FnvHash::Constants::DATE))
    {
      lexer->nextToken();
      string_ptr literal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      if (literal->length() > 2 &&
          literal->at(0) == '"' &&
          literal->at(literal->length() - 1) == '"')
      {
        literal = make_string_ptr(literal->substr(1, literal->length() - 2));
      }
      lexer->nextToken();
      // sqlExpr = new SQLDateExpr(literal);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::T))
    {
      lexer->nextToken();
      string_ptr literal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      // sqlExpr = new SQLTimeExpr(literal);
    }
    else if (lexer->identifierEquals(FnvHash::Constants::FN))
    {
      lexer->nextToken();
      sqlExpr = this->getExpr();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str())
    {
      sqlExpr = this->getExpr(); // {identifier expr} is ODBC escape syntax and is accepted for ODBC compatibility.
    }
    else
    {
      throw new ParserException(make_string_ptr("ERROR. " + encode_util::UnicodeToUTF8(lexer->info())));
    }
    accept(Token::RBRACE);
  }
  else if (
      tok->name->c_str() == Token::VALUES.name->c_str() ||
      tok->name->c_str() == Token::TRIGGER.name->c_str() ||
      tok->name->c_str() == Token::FOR.name->c_str() ||
      tok->name->c_str() == Token::CHECK.name->c_str() ||
      tok->name->c_str() == Token::DELETE.name->c_str() ||
      tok->name->c_str() == Token::BY.name->c_str() ||
      tok->name->c_str() == Token::UPDATE.name->c_str() ||
      tok->name->c_str() == Token::LOOP.name->c_str() ||
      tok->name->c_str() == Token::LIKE.name->c_str() ||
      tok->name->c_str() == Token::UNION.name->c_str() ||
      tok->name->c_str() == Token::CREATE.name->c_str() ||
      tok->name->c_str() == Token::COMMA.name->c_str() ||
      tok->name->c_str() == Token::STAR.name->c_str() ||
      tok->name->c_str() == Token::DIV.name->c_str() ||
      tok->name->c_str() == Token::DISTRIBUTE.name->c_str() ||
      tok->name->c_str() == Token::UNIQUE.name->c_str() ||
      tok->name->c_str() == Token::PROCEDURE.name->c_str() ||
      tok->name->c_str() == Token::REFERENCES.name->c_str() ||
      tok->name->c_str() == Token::IS.name->c_str() ||
      tok->name->c_str() == Token::REVOKE.name->c_str() ||
      tok->name->c_str() == Token::DECLARE.name->c_str() ||
      tok->name->c_str() == Token::DROP.name->c_str() ||
      tok->name->c_str() == Token::RLIKE.name->c_str() ||
      tok->name->c_str() == Token::FOREIGN.name->c_str() ||
      tok->name->c_str() == Token::FETCH.name->c_str() ||
      tok->name->c_str() == Token::ASC.name->c_str() ||
      tok->name->c_str() == Token::CURSOR.name->c_str() ||
      tok->name->c_str() == Token::ALTER.name->c_str())
  {
    if (dbType->name->c_str() == DbType::odps.name->c_str() ||
        dbType->name->c_str() == DbType::hive.name->c_str())
    {
      string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
      lexer->nextToken();
      goto out;
    }
    throw new ParserException(make_string_ptr("ERROR. " + encode_util::UnicodeToUTF8(lexer->info())));
  }
  else if (tok->name->c_str() == Token::AS.name->c_str())
  {

    if (dbType->name->c_str() == DbType::odps.name->c_str())
    {
      Lexer_SavePoint_ptr mark = lexer->mark();
      string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str() ||
          lexer->token()->name->c_str() == Token::RPAREN.name->c_str() ||
          lexer->token()->name->c_str() == Token::AS.name->c_str() ||
          lexer->token()->name->c_str() == Token::EQ.name->c_str() ||
          lexer->token()->name->c_str() == Token::EQEQ.name->c_str() ||
          lexer->token()->name->c_str() == Token::LT.name->c_str() ||
          lexer->token()->name->c_str() == Token::LTEQ.name->c_str() ||
          lexer->token()->name->c_str() == Token::GT.name->c_str() ||
          lexer->token()->name->c_str() == Token::GTEQ.name->c_str() ||
          lexer->token()->name->c_str() == Token::LTGT.name->c_str() ||
          lexer->token()->name->c_str() == Token::SEMI.name->c_str())
      {
        sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(str));
      }
      else if (lexer->token()->name->c_str() == Token::DOT.name->c_str())
      {
        sqlExpr = primaryRest(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(str)));
      }
      else
      {
        lexer->reset(mark);
      }
    }
  }
  else if (tok->name->c_str() == Token::DISTINCT.name->c_str())
  {

    if (dbType->name->c_str() == DbType::elastic_search.name->c_str() ||
        dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      Lexer_SavePoint_ptr mark = lexer->mark();
      string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
      lexer->nextToken();

      if (lexer->token()->name->c_str() != Token::LPAREN.name->c_str())
      {
        lexer->reset(mark);
        throw new ParserException(make_string_ptr("ERROR. " + encode_util::UnicodeToUTF8(lexer->info())));
      }
      goto out;
    }
    throw new ParserException(make_string_ptr("ERROR. " + encode_util::UnicodeToUTF8(lexer->info())));
  }
  else if (tok->name->c_str() == Token::BETWEEN.name->c_str() ||
           tok->name->c_str() == Token::IN.name->c_str())
  {
    if (dbType->name->c_str() == DbType::odps.name->c_str())
    {
      string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::DOT.name->c_str() ||
          lexer->token()->name->c_str() == Token::COMMA.name->c_str() ||
          lexer->token()->name->c_str() == Token::LT.name->c_str() ||
          lexer->token()->name->c_str() == Token::EQ.name->c_str() ||
          lexer->token()->name->c_str() == Token::GT.name->c_str() ||
          lexer->token()->name->c_str() == Token::RPAREN.name->c_str() ||
          lexer->token()->name->c_str() == Token::IS.name->c_str() ||
          lexer->token()->name->c_str() == Token::AS.name->c_str())
      {
        sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(str));
      }
      else
      {
        goto out;
      }
      if (sqlExpr != NULL)
      {
        goto out;
      }

      accept(Token::LPAREN);
      SQLInListExpr_ptr in = SQLInListExpr_ptr(new SQLInListExpr());
      in->setExpr(this->getExpr());
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        this->exprList(in->getTargetList(), in);
      }
      accept(Token::RPAREN);
      sqlExpr = in;
      goto out;
    }
    throw new ParserException(make_string_ptr("ERROR. " + encode_util::UnicodeToUTF8(lexer->info())));
  }
  else if (tok->name->c_str() == Token::LBRACKET.name->c_str())
  {

    if (dbType->name->c_str() == DbType::odps.name->c_str() ||
        dbType->name->c_str() == DbType::clickhouse.name->c_str())
    {
      // SQLArrayExpr* array = new SQLArrayExpr();
      // lexer->nextToken();
      // this->exprList(array->getValues(), array);
      // accept(Token::RBRACKET);
      // sqlExpr = array;
    }
    throw new ParserException(make_string_ptr("ERROR. " + encode_util::UnicodeToUTF8(lexer->info())));
  }
  else if (tok->name->c_str() == Token::ON.name->c_str())
  {

    if (dbType->name->c_str() == DbType::postgresql.name->c_str())
    {
      string_ptr methodName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
      {
        sqlExpr = this->methodRest(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(methodName)), BOOL::TRUE);
        goto out;
      }
    }
    throw new ParserException(make_string_ptr("ERROR. " + encode_util::UnicodeToUTF8(lexer->info())));
  }
  else if (tok->name->c_str() == Token::COLONCOLON.name->c_str())
  {

    if (dbType->name->c_str() == DbType::odps.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr temp = this->primary();
      // if (instanceof<SQLExpr, SQLArrayExpr>(temp))
      // {
      //   sqlExpr = temp;
      // }
      // else
      // {
      SQLMethodInvokeExpr_ptr method = std::dynamic_pointer_cast<SQLMethodInvokeExpr>(temp);
      string_ptr tmp = make_string_ptr("");
      method->setOwner(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp)));
      sqlExpr = method;
      // }
      goto out;
    }
    throw new ParserException(make_string_ptr("ERROR. " + encode_util::UnicodeToUTF8(lexer->info())));
  }
  else if (tok->name->c_str() == Token::ARRAY.name->c_str())
  {

    // SQLArrayExpr* array = new SQLArrayExpr();
    // array->setExpr(new SQLIdentifierExpr("ARRAY"));
    // lexer->nextToken();

    // accept(Token::LBRACKET);
    // this->exprList(array->getValues(), array);
    // accept(Token::RBRACKET);
    // sqlExpr = array;
  }
  else
  {
    std::string tmp = "ERROR. " + encode_util::UnicodeToUTF8(lexer->info());
    LOG_INFO << tmp;
    throw new ParserException(make_string_ptr(tmp));
  }
out:
  LOG_DEBUG << "goto primaryRest dbType->name->c_str():" << dbType->name->c_str();
  SQLExpr_ptr expr = nullptr;
  // if (pObj != nullptr && dbType->name->c_str() == DbType::mysql.name->c_str())
  // {
  //   LOG_DEBUG << "pObj != nullptr && dbType->name->c_str() == DbType::mysql.name->c_str()";
  //   expr = ((MySqlExprParser *)pObj)->primaryRest(sqlExpr);
  // }
  // else
  // {
  // LOG_DEBUG << "else";
  expr = primaryRest(sqlExpr);
  // }
  // LOG_DEBUG << "beforeComments:" << beforeComments;
  // if (!beforeComments->empty())
  if (beforeComments != nullptr)
  {
    string_list_ptr tmp = std::make_shared<std::list<string_ptr>>();
    for (auto it : *beforeComments)
    {
      tmp->push_back(make_string_ptr(encode_util::UnicodeToUTF8(*it)));
    }
    expr->addBeforeComment(tmp);
  }

  LOG_INFO << "return";
  return expr;
}

SQLExpr_ptr SQLExprParser::parseInterval()
{
  throw new ParserException(make_string_ptr("TODO"));
}

SQLSelectParser_ptr SQLExprParser::createSelectParser()
{
  return SQLSelectParser_ptr(new SQLSelectParser(SQLExprParser_ptr(this)));
}

SQLExpr_ptr SQLExprParser::primaryRest(SQLExpr_ptr expr)
{
  if (expr == NULL)
  {
    throw new IllegalArgumentException(make_string_ptr("expr"));
  }
  LOG_INFO << "; token name:" << lexer->token()->getName()->c_str();
  // LOG_INFO << expr->getText();
  if (lexer->token()->name->c_str() == Token::OF.name->c_str())
  {
    SQLIdentifierExpr_ptr v = std::dynamic_pointer_cast<SQLIdentifierExpr>(expr);
    if (v != 0)
    {

      string_ptr name = v->getName();

      if (StringUtils::iequals("CURRENT", name->c_str()))
      {
        lexer->nextToken();
        SQLName_ptr cursorName = getName();
        // delete expr;
        return SQLCurrentOfCursorExpr_ptr(new SQLCurrentOfCursorExpr(cursorName));
      }

      // if (string_ptr ("CURRENT").equalsIgnoreCase(name)) {
      // }
    }
  }

  LOG_INFO << "token name:" << lexer->token()->getName()->c_str();
  if (lexer->token()->name->c_str() == Token::DOT.name->c_str())
  {
    lexer->nextToken();

    // if (expr instanceof SQLCharExpr) {

    SQLCharExpr_ptr v = std::dynamic_pointer_cast<SQLCharExpr>(expr);
    if (v != 0)
    {
      string_ptr text = v->getText();
      SQLExpr_ptr x = expr;
      // delete expr;
      expr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr((text)));
    }

    expr = dotRest(expr);
    return primaryRest(expr);
  }
  else
  {
    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      return methodRest(expr, BOOL::TRUE);
    }
  }

  return expr;
}

SQLExpr_ptr SQLExprParser::methodRest(SQLExpr_ptr expr, BOOL_ptr acceptLEFTPAREN)
{

  // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLExprParser::methodRest, step 1 " <<   lexer->token()->name->c_str() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos();;
  if (acceptLEFTPAREN)
  {
    accept(Token::LPAREN);
  }

  SQLName_ptr n = std::dynamic_pointer_cast<SQLName>(expr);
  SQLDefaultExpr_ptr d = std::dynamic_pointer_cast<SQLDefaultExpr>(expr);
  // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLExprParser::methodRest, step 2 " <<   lexer->token()->name->c_str() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos();;
  // if (expr instanceof SQLName || expr instanceof SQLDefaultExpr) {
  if (n != 0 || d != 0)
  {
    // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLExprParser::methodRest, step 3 " <<   lexer->token()->name->c_str() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos();;
    string_ptr methodName;

    SQLMethodInvokeExpr_ptr methodInvokeExpr;
    methodInvokeExpr = NULL;
    SQLObject_ptr theExpr;

    SQLPropertyExpr_ptr p = std::dynamic_pointer_cast<SQLPropertyExpr>(expr);

    // if (expr instanceof SQLPropertyExpr) {
    if (p != 0)
    {
      // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLExprParser::methodRest, step 4 " <<   lexer->token()->name->c_str() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos();;
      methodName = p->getName();
      methodInvokeExpr = SQLMethodInvokeExpr_ptr(new SQLMethodInvokeExpr(methodName));

      // std::cout << "\t\t" <<  __FILE__ << ": " << __LINE__ << ", SQLExprParser::methodRest, occurs 1" ;;

      methodInvokeExpr->setOwner(p->getOwner());
      // delete p;
    }
    else
    {
      methodName = expr->toString();
      // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLExprParser::methodRest, step 5 " <<   lexer->token()->name->c_str() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos()<< ", methodName is: " << methodName <<  std::endl;
      methodInvokeExpr = SQLMethodInvokeExpr_ptr(new SQLMethodInvokeExpr(methodName));
      // delete n;
    }

    if (isAggreateFunction(methodName))
    {
      // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLExprParser::methodRest, step 6 " <<   lexer->token()->name->c_str() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos();;
      SQLAggregateExpr_ptr aggregateExpr = SQLAggregateExpr_ptr(parseAggregateExpr(methodName));

      // here the methodInvokeExpr created above will be lost.
      // if (methodInvokeExpr != NULL)
      // {
      //   delete methodInvokeExpr;
      // }

      return aggregateExpr;
    }

    if (lexer->token()->name->c_str() != Token::RPAREN.name->c_str())
    {

      // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLExprParser::methodRest, step 7 " <<   lexer->token()->name->c_str() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos();;
      theExpr = methodInvokeExpr;
      exprList(methodInvokeExpr->getParameters(), theExpr);
    }

    accept(Token::RPAREN);

    // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLExprParser::methodRest, step 8 " <<   lexer->token()->name->c_str() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->getStringVal()  <<  ", pos "  <<  lexer->getPos();;
    return primaryRest(SQLMethodInvokeExpr_ptr(methodInvokeExpr));
  }
  // throw new ParserException(string_ptr ("not support token:") + tokenStringList.at(lexer->token()->name->c_str()));
  throw new ParserException(make_string_ptr("not support token:"));
}

SQLExpr_ptr SQLExprParser::dotRest(SQLExpr_ptr expr)
{
  if (lexer->token()->name->c_str() == Token::STAR.name->c_str())
  {
    lexer->nextToken();

    string_ptr star = make_string_ptr("*");
    expr = SQLPropertyExpr_ptr(new SQLPropertyExpr(expr, star));
  }
  else
  {
    string_ptr name;

    if (lexer->token() == Token_ptr(new Token(&Token::IDENTIFIER)) ||
        lexer->token() == Token_ptr(new Token(&Token::LITERAL_CHARS)) ||
        lexer->token() == Token_ptr(new Token(&Token::LITERAL_ALIAS)))
    {

      name = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
    }
    else if (lexer->getKeywords()->containsValue(lexer->token()))
    {

      name = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
    }
    else
    {

      throw new ParserException(make_string_ptr("error : " + encode_util::UnicodeToUTF8(*lexer->stringVal())));
    }

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {

      lexer->nextToken();

      SQLMethodInvokeExpr_ptr methodInvokeExpr = SQLMethodInvokeExpr_ptr(new SQLMethodInvokeExpr(name));
      // std::cout << "\t\t" <<  __FILE__ << ": " << __LINE__ << ", SQLExprParser::methodRest, occurs 2" ;;
      methodInvokeExpr->setOwner(expr);

      if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
      {
        lexer->nextToken();
      }
      else
      {
        if (lexer->token()->name->c_str() == Token::PLUS.name->c_str())
        {
          string_ptr plus1 = make_string_ptr("*");
          methodInvokeExpr->addParameter(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(plus1)));
          lexer->nextToken();
        }
        else
        {

          exprList(methodInvokeExpr->getParameters(), methodInvokeExpr);
        }
        accept(Token::RPAREN);
      }
      expr = methodInvokeExpr;
    }
    else
    {
      expr = SQLPropertyExpr_ptr(new SQLPropertyExpr(expr, name));
    }
  }

  expr = primaryRest(expr);
  return expr;
}

SQLExpr_ptr SQLExprParser::groupComparisionRest(SQLExpr_ptr expr)
{
  return expr;
}

void SQLExprParser::getNames(SQLName_list_ptr exprCol)
{
  SQLObject_ptr obj = SQLObject_ptr(new SQLObject());
  getNames(exprCol, obj);
}

void SQLExprParser::getNames(SQLName_list_ptr exprCol, SQLObject_ptr parent)
{
  if (lexer->token()->name->c_str() == Token::RBRACE.name->c_str())
  {
    return;
  }

  if (lexer->token()->name->c_str() == Token::XEOF.name->c_str())
  {
    return;
  }

  SQLName_ptr name = getName();
  // name->setParent(parent);
  exprCol->push_back(name);

  while (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
  {
    lexer->nextToken();

    name = getName();
    // name->setParent(parent);
    exprCol->push_back(name);
  }
}

void SQLExprParser::exprList(SQLExpr_list_ptr exprCol)
{
  SQLObject_ptr sqlObj = SQLObject_ptr(new SQLObject());
  exprList(exprCol, sqlObj);
}

void SQLExprParser::exprList(SQLExpr_list_ptr exprCol, SQLObject_ptr parent)
{
  LOG_INFO << "token name:" << lexer->token()->getName() << " " << lexer->stringVal();
  if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str() ||
      lexer->token()->name->c_str() == Token::RBRACKET.name->c_str() ||
      lexer->token()->name->c_str() == Token::SEMI.name->c_str())
  {
    return;
  }

  if (lexer->token()->name->c_str() == Token::XEOF.name->c_str())
  {
    return;
  }

  LOG_INFO << "goto getExpr";
  SQLExpr_ptr expr = getExpr();
  LOG_INFO << "goto setParent";
  expr->setParent(parent);
  exprCol->push_back(expr);

  LOG_INFO << "token name:" << lexer->token()->getName();
  while (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
  {
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName() << " " << lexer->stringVal();
    LOG_INFO << "goto getExpr";
    expr = getExpr();
    LOG_INFO << "goto setParent";
    expr->setParent(parent);
    exprCol->push_back(expr);
  }
}

SQLName_ptr SQLExprParser::getName()
{
  string_ptr identName;
  LOG_INFO << "token name:" << lexer->token()->getName()->c_str();

  if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
  {
    identName = make_string_ptr("\"" + encode_util::UnicodeToUTF8(*lexer->stringVal()) + "\"");
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
  {
    identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    LOG_INFO;
    lexer->nextToken();
    LOG_INFO;
  }
  else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
  {
    identName = make_string_ptr("\'" + encode_util::UnicodeToUTF8(*lexer->stringVal()) + "\'");
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::VARIANT.name->c_str())
  {
    identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
  }
  else
  {
    if (/* lexer->token()->name->c_str() == Token::MODEL || */
        lexer->token()->name->c_str() == Token::PCTFREE.name->c_str() ||
        lexer->token()->name->c_str() == Token::INITRANS.name->c_str() ||
        lexer->token()->name->c_str() == Token::MAXTRANS.name->c_str() ||
        lexer->token()->name->c_str() == Token::SEGMENT.name->c_str() ||
        lexer->token()->name->c_str() == Token::CREATION.name->c_str() ||
        lexer->token()->name->c_str() == Token::IMMEDIATE.name->c_str() ||
        lexer->token()->name->c_str() == Token::DEFERRED.name->c_str() ||
        lexer->token()->name->c_str() == Token::STORAGE.name->c_str() ||
        lexer->token()->name->c_str() == Token::NEXT.name->c_str() ||
        lexer->token()->name->c_str() == Token::MINEXTENTS.name->c_str() ||
        lexer->token()->name->c_str() == Token::MAXEXTENTS.name->c_str() ||
        lexer->token()->name->c_str() == Token::MAXSIZE.name->c_str() ||
        lexer->token()->name->c_str() == Token::PCTINCREASE.name->c_str() ||
        lexer->token()->name->c_str() == Token::FLASH_CACHE.name->c_str() ||
        lexer->token()->name->c_str() == Token::CELL_FLASH_CACHE.name->c_str() ||
        /* lexer->token()->name->c_str() == Token::KEEP.name->c_str() || */
        lexer->token()->name->c_str() == Token::NONE.name->c_str() ||
        lexer->token()->name->c_str() == Token::LOB.name->c_str() ||
        lexer->token()->name->c_str() == Token::STORE.name->c_str() ||
        lexer->token()->name->c_str() == Token::ROW.name->c_str() ||
        lexer->token()->name->c_str() == Token::CHUNK.name->c_str() ||
        lexer->token()->name->c_str() == Token::CACHE.name->c_str() ||
        lexer->token()->name->c_str() == Token::NOCACHE.name->c_str() ||
        lexer->token()->name->c_str() == Token::LOGGING.name->c_str() ||
        lexer->token()->name->c_str() == Token::NOCOMPRESS.name->c_str() ||
        lexer->token()->name->c_str() == Token::KEEP_DUPLICATES.name->c_str() ||
        lexer->token()->name->c_str() == Token::EXCEPTIONS.name->c_str() ||
        lexer->token()->name->c_str() == Token::PURGE.name->c_str() ||
        lexer->token()->name->c_str() == Token::INITIALLY.name->c_str() ||
        lexer->token()->name->c_str() == Token::END.name->c_str() ||
        lexer->token()->name->c_str() == Token::COMMENT.name->c_str() ||
        lexer->token()->name->c_str() == Token::ENABLE.name->c_str() ||
        lexer->token()->name->c_str() == Token::DISABLE.name->c_str() ||
        lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str() ||
        lexer->token()->name->c_str() == Token::USER.name->c_str() ||
        lexer->token()->name->c_str() == Token::ANALYZE.name->c_str() ||
        lexer->token()->name->c_str() == Token::OPTIMIZE.name->c_str() ||
        lexer->token()->name->c_str() == Token::GRANT.name->c_str())
    {
      identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      LOG_INFO << "identName:" << identName;
      lexer->nextToken();
    }
    else
    {
      std::string stream;
      // stream << "error  " << __FILE__ << ": " << __LINE__ << ": " << lexer->token()->name->c_str() << ": " << tokenStringList.at(lexer->token()->name->c_str()) << ": stringVal is: " << lexer->stringVal();
      stream = "error  ";
      stream += __FILE__;
      stream += ": ";
      stream += std::to_string(__LINE__);
      stream += ": ";
      // stream += lexer->token()->name->c_str() ;
      stream += ": ";
      stream += ": stringVal is: ";
      stream += encode_util::UnicodeToUTF8(*lexer->stringVal());

      // std::cout << "===>\t" <<  stream.str() ;;
      throw new ParserException(make_string_ptr(stream));
      // throw new ParserException("error " + lexer->token()->name->c_str());
    }
  }

  LOG_INFO;
  SQLName_ptr name = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(identName));

  LOG_INFO;
  name = nameRest(name);
  LOG_INFO;

  return name;
}

SQLName_ptr SQLExprParser::nameRest(SQLName_ptr name)
{
  LOG_INFO << "token name:" << lexer->token()->name->c_str();
  if (lexer->token()->name->c_str() == Token::DOT.name->c_str())
  {
    lexer->nextToken();

    LOG_INFO << "token name:" << lexer->token()->name->c_str();
    if (lexer->token()->name->c_str() == Token::KEY.name->c_str())
    {
      string_ptr key1 = make_string_ptr("KEY");
      name = SQLPropertyExpr_ptr(new SQLPropertyExpr(name, key1));
      lexer->nextToken();
      return name;
    }

    if (lexer->token()->name->c_str() != Token::LITERAL_ALIAS.name->c_str() &&
        lexer->token()->name->c_str() != Token::IDENTIFIER.name->c_str() &&
        (!lexer->getKeywords()->containsValue(lexer->token())))
    {

      // throw new ParserException(string_ptr ("error, ") + tokenStringList.at(lexer->token()->name->c_str()));
      throw new ParserException(make_string_ptr("error, "));
    }

    if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      string_ptr x = make_string_ptr("\"" + encode_util::UnicodeToUTF8(*lexer->stringVal()) + "\"");
      name = SQLPropertyExpr_ptr(new SQLPropertyExpr(name, x));
    }
    else
    {
      string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      LOG_INFO << "stringVal:" << tmp->c_str();
      name = SQLPropertyExpr_ptr(new SQLPropertyExpr(name, tmp));
    }
    LOG_INFO;
    lexer->nextToken();
    LOG_INFO;
    name = nameRest(name);
  }

  return name;
}

BOOL_ptr SQLExprParser::isAggreateFunction(string_ptr word)
{

  // for (int i = 0; i < aggregateFunctions.length; ++i) {
  // if (aggregateFunctions[i].compareToIgnoreCase(word) == 0) {
  // return BOOL::TRUE;
  //}
  //}
  /*
    string_ptr  newstr = boost::to_upper_copy(word);
    if(binary_search(aggregateFunctions.begin(), aggregateFunctions.end(), newstr)){
         // Find the item
       return BOOL::TRUE;
    }
  */

  int size = sizeof(aggregateFunctions);
  for (int i = 0; i < size; i++)
  {
    if (StringUtils::iequals(aggregateFunctions->at(i)->c_str(), word->c_str()))
    {
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}

SQLAggregateExpr_ptr SQLExprParser::parseAggregateExpr(string_ptr methodName)
{
  // methodName = methodName.toUpperCase();
  methodName = StringUtils::toUpper(methodName);

  SQLAggregateExpr_ptr aggregateExpr;

  if (lexer->token()->name->c_str() == Token::ALL.name->c_str())
  {
    auto tmp = SQLAggregateOption::ALL;
    aggregateExpr = SQLAggregateExpr_ptr(new SQLAggregateExpr(methodName, tmp));
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::DISTINCT.name->c_str())
  {
    auto tmp = SQLAggregateOption::DISTINCT;
    aggregateExpr = SQLAggregateExpr_ptr(new SQLAggregateExpr(methodName, tmp));
    lexer->nextToken();
  }
  else
  {

    aggregateExpr = SQLAggregateExpr_ptr(new SQLAggregateExpr(methodName));
  }

  exprList(aggregateExpr->getArguments(), aggregateExpr);

  parseAggregateExprRest(aggregateExpr);

  accept(Token::RPAREN);

  if (lexer->token()->name->c_str() == Token::OVER.name->c_str())
  {

    // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLExprParser::parseAggregateExpr, for over" <<   lexer->token()->name->c_str() <<  " " << tokenStringList.at(lexer->token()->name->c_str() ) <<  ": "  <<  lexer->stringVal()  <<  ", pos "  <<  lexer->getPos();;
    lexer->nextToken();
    SQLOver_ptr over = SQLOver_ptr(new SQLOver());
    accept(Token::LPAREN);

    if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str() || identifierEquals("PARTITION"))
    {
      lexer->nextToken();
      accept(Token::BY);

      if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
      {
        lexer->nextToken();
        exprList(over->getPartitionBy());
        accept(Token::RPAREN);
      }
      else
      {
        exprList(over->getPartitionBy());
      }
    }

    over->setOrderBy(parseOrderBy());

    accept(Token::RPAREN);
    aggregateExpr->setOver(over);
  }

  return aggregateExpr;
}

SQLAggregateExpr_ptr SQLExprParser::parseAggregateExprRest(SQLAggregateExpr_ptr aggregateExpr)
{
  return aggregateExpr;
}

SQLOrderBy_ptr SQLExprParser::parseOrderBy()
{
  LOG_INFO << ":"
           << ", in  step 1 " << lexer->token()->getName() << ": " << lexer->stringVal() << ", pos " << lexer->pos();
  if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
  {
    LOG_INFO << ":"
             << ", in  step 1.1 " << lexer->token()->getName() << ": " << lexer->stringVal() << ", pos " << lexer->pos();
    SQLOrderBy_ptr orderBy_ = SQLOrderBy_ptr(new SQLOrderBy());

    LOG_INFO << ":";
    lexer->nextToken();

    LOG_INFO << ":";
    if (lexer->identifierEquals(FnvHash::Constants::SIBLINGS))
    {
      LOG_INFO << ":";
      lexer->nextToken();
      LOG_INFO << ":";
      orderBy_->setSiblings(BOOL::TRUE);
    }

    LOG_INFO << ":";
    accept(Token::BY);

    LOG_INFO << ":" << orderBy_->toString() << "," << lexer->token()->getName() << ": " << lexer->stringVal();
    orderBy(orderBy_->getItems(), orderBy_);

    LOG_INFO << ":" << encode_util::UnicodeToUTF8(lexer->info()) << ",stringval:" << encode_util::UnicodeToUTF8(*lexer->stringVal());
    if (lexer->token()->name->c_str() == Token::ORDER.name->c_str())
    {
      throw new ParserException(make_string_ptr(encode_util::UnicodeToUTF8(lexer->info()))); // dual order by
    }

    // orderBy->getItems().push_back(parseSelectOrderByItem());

    // while (lexer->token()->name->c_str() == Token::COMMA)
    // {
    //   LOG_INFO << ":token name:" << lexer->token()->getName();
    //   lexer->nextToken();
    //   orderBy->getItems().push_back(parseSelectOrderByItem());
    // }

    LOG_INFO << ", in , step 1.2 " << lexer->token()->getName() << ": " << lexer->stringVal() << ", pos " << lexer->pos();
    return orderBy_;
  }

  LOG_INFO << ", in , step 2 " << lexer->token()->getName() << ": " << lexer->stringVal() << ", pos " << lexer->pos();
  return NULL;
}

SQLSelectOrderByItem_ptr SQLExprParser::parseSelectOrderByItem()
{
  SQLSelectOrderByItem_ptr item = SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem());

  setAllowIdentifierMethod(BOOL::FALSE);

  LOG_INFO << "token name:" << lexer->token()->getName();
  try
  {
    SQLExpr_ptr expr;
    if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
    {
      expr = name();
      expr = primaryRest(expr);
      expr = exprRest(expr);
    }
    else if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      Lexer_SavePoint_ptr mark = lexer->mark();
      lexer->nextToken();
      LOG_INFO << "token name:" << lexer->token()->getName();
      for (int i = 0;; ++i)
      {
        LOG_INFO << "token name:" << lexer->token()->getName();
        expr = this->getExpr();
        if (lexer->token()->name->c_str() == Token::ASC.name->c_str())
        {
          lexer->nextToken();
          LOG_INFO << "token name:" << lexer->token()->getName();
          item->setType(SQLOrderingSpecification_ptr(new SQLOrderingSpecification(&SQLOrderingSpecification::ASC)));
          if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
          {
            lexer->nextToken();
            LOG_INFO << "token name:" << lexer->token()->getName();
            continue;
          }
          accept(Token::RPAREN);
        }
        else if (lexer->token()->name->c_str() == Token::DESC.name->c_str())
        {
          lexer->nextToken();
          LOG_INFO << "token name:" << lexer->token()->getName();
          item->setType(SQLOrderingSpecification_ptr(new SQLOrderingSpecification(&SQLOrderingSpecification::DESC)));
          if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
          {
            lexer->nextToken();
            LOG_INFO << "token name:" << lexer->token()->getName();
            continue;
          }
          accept(Token::RPAREN);
        }
        else
        {
          if (i > 0 && lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
          {
            lexer->nextToken();
            LOG_INFO << "token name:" << lexer->token()->getName();
            break;
          }
          lexer->reset(mark);
          expr = getExpr();
        }
        break;
      }
    }
    else
    {
      expr = getExpr();
    }

    if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))))
    {
      if (instanceof <SQLExpr, SQLPropertyExpr>(expr))
      {
        SQLPropertyExpr_ptr propertyExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(expr);
        SQLExpr_ptr owner = propertyExpr->getOwner();
        if (owner != NULL)
        {
          string_ptr ownerStr = SQLUtils::toSQLString(owner);
          if (ownerStr->length() > 1)
          {
            ownerStr = StringUtils::removeNameQuotes(ownerStr);
          }
          propertyExpr->setOwner(ownerStr);
        }
        string_ptr name = propertyExpr->getName();
        if (name->length() > 1)
        {
          name = StringUtils::removeNameQuotes(name);
          propertyExpr->setName(name);
        }
        expr = propertyExpr;
      }
    }
    item->setExpr(expr);
  }
  catch (...)
  {
    LOG_INFO << "catch";
  }
  setAllowIdentifierMethod(BOOL::TRUE);

  if (lexer->identifierEquals(FnvHash::Constants::COLLATE))
  {
    LOG_INFO;
    lexer->nextToken();
    string_ptr collate = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    item->setCollate(collate);
    lexer->nextToken();
  }

  LOG_INFO << "token name:" << lexer->token()->getName();
  if (lexer->token()->name->c_str() == Token::ASC.name->c_str())
  {
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName();
    item->setType(SQLOrderingSpecification_ptr(new SQLOrderingSpecification(&SQLOrderingSpecification::ASC)));
  }
  else if (lexer->token()->name->c_str() == Token::DESC.name->c_str())
  {
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName();
    item->setType(SQLOrderingSpecification_ptr(new SQLOrderingSpecification(&SQLOrderingSpecification::DESC)));
  }

  if (lexer->identifierEquals(FnvHash::Constants::NULLS))
  {
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName();
    if (lexer->identifierEquals(FnvHash::Constants::FIRST) ||
        lexer->token()->name->c_str() == Token::FIRST.name->c_str())
    {
      lexer->nextToken();
      LOG_INFO << "token name:" << lexer->token()->getName();
      item->setNullsOrderType(SQLSelectOrderByItem_NullsOrderType_ptr(new SQLSelectOrderByItem_NullsOrderType(&SQLSelectOrderByItem_NullsOrderType::NullsFirst)));
    }
    else if (lexer->identifierEquals(FnvHash::Constants::LAST))
    {
      lexer->nextToken();
      LOG_INFO << "token name:" << lexer->token()->getName();
      item->setNullsOrderType(SQLSelectOrderByItem_NullsOrderType_ptr(new SQLSelectOrderByItem_NullsOrderType(&SQLSelectOrderByItem_NullsOrderType::NullsLast)));
    }
    else
    {
      std::string tmp = "TODO ";
      tmp += encode_util::UnicodeToUTF8(lexer->info());
      throw new ParserException(make_string_ptr(tmp));
    }
  }

  LOG_INFO << "token name:" << lexer->token()->getName();
  if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    LOG_INFO << "setHint";
    item->setHint(this->parseHint());
  }

  return item;
}

SQLExpr_ptr SQLExprParser::bitAnd()
{
  SQLExpr_ptr expr = shift();
  return bitAndRest(expr);
}

SQLExpr_ptr SQLExprParser::bitAndRest(SQLExpr_ptr expr)
{

  while (lexer->token()->name->c_str() == Token::AMP.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr rightExp = shift();
    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BitwiseAnd)), rightExp));
  }
  return expr;
}

SQLExpr_ptr SQLExprParser::bitOr()
{
  SQLExpr_ptr expr = bitAnd();
  return bitOrRest(expr);
}

SQLExpr_ptr SQLExprParser::bitOrRest(SQLExpr_ptr expr)
{
  if (lexer->token()->name->c_str() == Token::BAR.name->c_str())
  {
    lexer->nextToken();
    SQLExpr_ptr rightExp = bitAnd();
    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BitwiseOr)), rightExp));
    expr = bitAndRest(expr);
  }
  return expr;
}

SQLExpr_ptr SQLExprParser::equality()
{
  SQLExpr_ptr expr = bitOr();
  return equalityRest(expr);
}

SQLExpr_ptr SQLExprParser::equalityRest(SQLExpr_ptr expr)
{

  SQLExpr_ptr rightExp;
  if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
  {
    lexer->nextToken();
    try
    {
      rightExp = bitOr();
    }
    catch (EOFParserException e)
    {
      std::stringstream stream;
      stream << "XEOF, " << expr << "=" << e.what();
      throw new ParserException(make_string_ptr(stream.str()));
    }
    rightExp = equalityRest(rightExp);

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Equality)), rightExp));
  }
  else if (lexer->token()->name->c_str() == Token::BANGEQ.name->c_str())
  {
    lexer->nextToken();
    rightExp = bitOr();

    rightExp = equalityRest(rightExp);

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::NotEqual)), rightExp));
  }
  else if (lexer->token()->name->c_str() == Token::COLONEQ.name->c_str())
  {
    lexer->nextToken();
    rightExp = getExpr();
    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Assignment)), rightExp));
  }

  return expr;
}

SQLExpr_ptr SQLExprParser::inRest(SQLExpr_ptr expr)
{

  if (lexer->token()->name->c_str() == Token::IN.name->c_str())
  {
    lexer->nextToken();

    SQLInListExpr_ptr inListExpr = SQLInListExpr_ptr(new SQLInListExpr(expr));
    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {

      lexer->nextToken();
      exprList(inListExpr->getTargetList(), inListExpr);
      accept(Token::RPAREN);
      expr = inListExpr;
    }
    else
    {

      SQLExpr_ptr itemExpr = primary();
      // itemExpr->setParent(inListExpr);
      inListExpr->getTargetList()->push_back(itemExpr);
    }

    expr = inListExpr;

    if (inListExpr->getTargetList()->size() == 1)
    {
      // SQLExpr targetExpr = (inListExpr->getTargetList()).get(0);
      SQLExpr_ptr targetExpr = (inListExpr->getTargetList())->front();

      SQLQueryExpr_ptr q = std::dynamic_pointer_cast<SQLQueryExpr>(targetExpr);
      // if (targetExpr instanceof SQLQueryExpr) {
      if (q != 0)
      {

        SQLInSubQueryExpr_ptr inSubQueryExpr = SQLInSubQueryExpr_ptr(new SQLInSubQueryExpr());
        inSubQueryExpr->setExpr(inListExpr->getExpr());

        inSubQueryExpr->setSubQuery(q->getSubQuery());
        expr = inSubQueryExpr;
      }
    }
  }

  return expr;
}

SQLExpr_ptr SQLExprParser::additive()
{
  SQLExpr_ptr expr = multiplicative();
  return additiveRest(expr);
}

SQLExpr_ptr SQLExprParser::additiveRest(SQLExpr_ptr expr)
{

  if (lexer->token()->name->c_str() == Token::PLUS.name->c_str())
  {

    lexer->nextToken();
    SQLExpr_ptr rightExp = multiplicative();

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Add)), rightExp));
    expr = additiveRest(expr);
  }
  else if (lexer->token()->name->c_str() == Token::BARBAR.name->c_str())
  {

    lexer->nextToken();
    SQLExpr_ptr rightExp = multiplicative();
    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Concat)), rightExp));
    expr = additiveRest(expr);
  }
  else if (lexer->token()->name->c_str() == Token::SUB.name->c_str())
  {

    lexer->nextToken();
    SQLExpr_ptr rightExp = multiplicative();

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Subtract)), rightExp));
    expr = additiveRest(expr);
  }

  return expr;
}

SQLExpr_ptr SQLExprParser::shift()
{
  SQLExpr_ptr expr = additive();
  return shiftRest(expr);
}

SQLExpr_ptr SQLExprParser::shiftRest(SQLExpr_ptr expr)
{

  if (lexer->token()->name->c_str() == Token::LTLT.name->c_str())
  {

    lexer->nextToken();
    SQLExpr_ptr rightExp = additive();

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::LeftShift)), rightExp));
    expr = shiftRest(expr);
  }
  else if (lexer->token()->name->c_str() == Token::GTGT.name->c_str())
  {

    lexer->nextToken();
    SQLExpr_ptr rightExp = additive();

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::RightShift)), rightExp));
    expr = shiftRest(expr);
  }

  return expr;
}

SQLExpr_ptr SQLExprParser::getAnd()
{
  SQLExpr_ptr expr = relational();
  return andRest(expr);
}

SQLExpr_ptr SQLExprParser::andRest(SQLExpr_ptr expr)
{
  for (;;)
  {

    if (lexer->token()->name->c_str() == Token::AND.name->c_str() ||
        lexer->token()->name->c_str() == Token::AMPAMP.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr rightExp = relational();

      expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BooleanAnd)), rightExp));
    }
    else
    {
      break;
    }
  }

  return expr;
}

SQLExpr_ptr SQLExprParser::getOr()
{
  SQLExpr_ptr expr = getAnd();
  return orRest(expr);
}

SQLExpr_ptr SQLExprParser::orRest(SQLExpr_ptr expr)
{

  for (;;)
  {
    if (lexer->token()->name->c_str() == Token::OR.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr rightExp = getAnd();

      expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BooleanOr)), rightExp));
    }
    else if (lexer->token()->name->c_str() == Token::XOR.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr rightExp = getAnd();

      expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BooleanXor)), rightExp));
    }
    else
    {
      break;
    }
  }

  return expr;
}

SQLExpr_ptr SQLExprParser::relational()
{
  SQLExpr_ptr expr = equality();

  return relationalRest(expr);
}

SQLExpr_ptr SQLExprParser::relationalRest(SQLExpr_ptr expr)
{
  SQLExpr_ptr rightExp;

  if (lexer->token()->name->c_str() == Token::LT.name->c_str())
  {
    SQLBinaryOperator *op = &SQLBinaryOperator::LessThan;

    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
      op = &SQLBinaryOperator::LessThanOrEqual;
    }

    rightExp = bitOr();
    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(op)), rightExp));
    // expr = relationalRest(expr);
  }
  else if (lexer->token()->name->c_str() == Token::LTEQ.name->c_str())
  {
    lexer->nextToken();
    rightExp = bitOr();

    // rightExp = relationalRest(rightExp);

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::LessThanOrEqual)), rightExp));
  }
  else if (lexer->token()->name->c_str() == Token::LTEQGT.name->c_str())
  {
    lexer->nextToken();
    rightExp = bitOr();

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::LessThanOrEqualOrGreaterThan)), rightExp));
  }
  else if (lexer->token()->name->c_str() == Token::GT.name->c_str())
  {
    SQLBinaryOperator *op = &SQLBinaryOperator::GreaterThan;

    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      lexer->nextToken();
      op = &SQLBinaryOperator::GreaterThanOrEqual;
    }

    rightExp = bitOr();

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(op)), rightExp));
  }
  else if (lexer->token()->name->c_str() == Token::GTEQ.name->c_str())
  {

    lexer->nextToken();
    rightExp = bitOr();

    // rightExp = relationalRest(rightExp);

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::GreaterThanOrEqual)), rightExp));
  }
  else if (lexer->token()->name->c_str() == Token::BANGLT.name->c_str())
  {

    lexer->nextToken();
    rightExp = bitOr();

    // rightExp = relationalRest(rightExp);

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::NotLessThan)), rightExp));
  }
  else if (lexer->token()->name->c_str() == Token::BANGGT.name->c_str())
  {

    lexer->nextToken();
    rightExp = bitOr();

    rightExp = relationalRest(rightExp);

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::NotGreaterThan)), rightExp));
  }
  else if (lexer->token()->name->c_str() == Token::LTGT.name->c_str())
  {

    lexer->nextToken();
    rightExp = bitOr();

    // rightExp = relationalRest(rightExp);

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::LessThanOrGreater)), rightExp));
  }
  else if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
  {
    lexer->nextToken();
    rightExp = bitOr();

    // rightExp = relationalRest(rightExp);

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Like)), rightExp));

    if (lexer->token()->name->c_str() == Token::ESCAPE.name->c_str())
    {

      lexer->nextToken();
      rightExp = primary();
      expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Escape)), rightExp));
    }
  }
  else if (lexer->token()->name->c_str() == (Token::NOT.name->c_str()))
  {

    lexer->nextToken();
    expr = notRationalRest(expr);
  }
  else if (lexer->token()->name->c_str() == (Token::BETWEEN.name->c_str()))
  {

    lexer->nextToken();
    SQLExpr_ptr beginExpr = bitOr();
    accept(Token::AND);
    SQLExpr_ptr endExpr = bitOr();
    expr = SQLBetweenExpr_ptr(new SQLBetweenExpr(expr, beginExpr, endExpr));
  }
  else if (lexer->token()->name->c_str() == (Token::IS.name->c_str()))
  {

    lexer->nextToken();

    if (lexer->token()->name->c_str() == (Token::NOT.name->c_str()))
    {

      lexer->nextToken();
      SQLExpr_ptr rightExpr = primary();
      expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::IsNot)), rightExpr));
    }
    else
    {
      SQLExpr_ptr rightExpr = primary();
      expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Is)), rightExpr));
    }
  }
  else if (lexer->token()->name->c_str() == Token::IN.name->c_str())
  {
    expr = inRest(expr);
  }

  return expr;
}

SQLExpr_ptr SQLExprParser::notRationalRest(SQLExpr_ptr expr)
{

  if (lexer->token()->name->c_str() == (Token::LIKE.name->c_str()))
  {
    lexer->nextToken();

    SQLExpr_ptr rightExp = equality();

    rightExp = relationalRest(rightExp);

    expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::NotLike)), rightExp));

    if (lexer->token()->name->c_str() == Token::ESCAPE.name->c_str())
    {
      lexer->nextToken();
      rightExp = getExpr();
      expr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(expr, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Escape)), rightExp));
    }
  }
  else if (lexer->token()->name->c_str() == Token::IN.name->c_str())
  {

    lexer->nextToken();
    accept(Token::LPAREN);

    SQLInListExpr_ptr inListExpr = SQLInListExpr_ptr(new SQLInListExpr(expr, BOOL::TRUE));
    exprList(inListExpr->getTargetList(), inListExpr);
    expr = inListExpr;

    accept(Token::RPAREN);

    if (inListExpr->getTargetList()->size() == 1)
    {

      // SQLExpr targetExpr = inListExpr.getTargetList().get(0);
      SQLExpr_ptr targetExpr = inListExpr->getTargetList()->front();

      SQLQueryExpr_ptr v = std::dynamic_pointer_cast<SQLQueryExpr>(targetExpr);

      // if (targetExpr instanceof SQLQueryExpr) {
      if (v != 0)
      {
        SQLInSubQueryExpr_ptr inSubQueryExpr = SQLInSubQueryExpr_ptr(new SQLInSubQueryExpr());
        inSubQueryExpr->setNot(BOOL::TRUE);
        inSubQueryExpr->setExpr(inListExpr->getExpr());
        inSubQueryExpr->setSubQuery(v->getSubQuery());
        expr = inSubQueryExpr;
      }
    }

    expr = relationalRest(expr);
    return expr;
  }
  else if (lexer->token()->name->c_str() == (Token::BETWEEN.name->c_str()))
  {
    lexer->nextToken();
    SQLExpr_ptr beginExpr = bitOr();
    accept(Token::AND);
    SQLExpr_ptr endExpr = bitOr();

    expr = SQLBetweenExpr_ptr(new SQLBetweenExpr(expr, BOOL::TRUE, beginExpr, endExpr));

    return expr;
  }
  else
  {
    // throw new ParserException("TODO " + lexer->token()->name->c_str());
    throw new ParserException(make_string_ptr("TODO "));
  }
  return expr;
}

SQLDataType_ptr SQLExprParser::parseDataTypeRest(SQLDataType_ptr dataType)
{
  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    lexer->nextToken();

    SQLDataTypeImpl_ptr v = std::dynamic_pointer_cast<SQLDataTypeImpl>(dataType);
    if (v != NULL)
    {
      exprList(v->getArguments(), dataType);
      accept(Token::RPAREN);
    }
  }

  return dataType;
}

BOOL_ptr SQLExprParser::isCharType(string_ptr dataTypeName)
{
  if (StringUtils::iequals(("char"), dataTypeName->c_str()) ||
      StringUtils::iequals(("varchar"), dataTypeName->c_str()) ||
      StringUtils::iequals(("nchar"), dataTypeName->c_str()) ||
      StringUtils::iequals(("nvarchar"), dataTypeName->c_str()) ||
      StringUtils::iequals(("tinytext"), dataTypeName->c_str()) ||
      StringUtils::iequals(("text"), dataTypeName->c_str()) ||
      StringUtils::iequals(("mediumtext"), dataTypeName->c_str()) ||
      StringUtils::iequals(("longtext"), dataTypeName->c_str()))
  {
    return BOOL::TRUE;
  }
  else
  {
    return BOOL::FALSE;
  }

  //"char".equalsIgnoreCase(dataTypeName) //
  //|| "varchar".equalsIgnoreCase(dataTypeName)
  //|| "nchar".equalsIgnoreCase(dataTypeName)
  //|| "nvarchar".equalsIgnoreCase(dataTypeName)
  //|| "tinytext".equalsIgnoreCase(dataTypeName)
  //|| "text".equalsIgnoreCase(dataTypeName)
  //|| "mediumtext".equalsIgnoreCase(dataTypeName)
  //|| "longtext".equalsIgnoreCase(dataTypeName)
  ////
  //;
}

SQLDataType_ptr SQLExprParser::parseCharTypeRest(SQLCharacterDataType_ptr charType)
{
  if (identifierEquals("CHARACTER"))
  {
    lexer->nextToken();

    accept(Token::SET);

    if (lexer->token()->name->c_str() != Token::IDENTIFIER.name->c_str() &&
        lexer->token()->name->c_str() != Token::LITERAL_CHARS.name->c_str())
    {
      throw new ParserException();
    }
    charType->setCharSetName(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {

      if (StringUtils::iequals(encode_util::UnicodeToUTF8(*lexer->stringVal()), ("COLLATE")))
      {
        lexer->nextToken();

        if (lexer->token()->name->c_str() != Token::IDENTIFIER.name->c_str())
        {
          throw new ParserException();
        }
        charType->setCollate(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
        lexer->nextToken();
      }
    }
  }
  return charType;
}

void SQLExprParser::accept(Token token)
{
  LOG_INFO << "lexer->token() name:" << lexer->token()->getName() << ", token name:" << token.getName();
  if (lexer->token()->name->c_str() == token.name->c_str())
  {
    lexer->nextToken();
    LOG_INFO << "token name:" << lexer->token()->getName();
  }
  else
  {
    throw new ParserException(make_string_ptr("syntax error, expect  " + encode_util::UnicodeToUTF8(*lexer->stringVal())));
  }
}

// SQLColumnDefinition_ptr SQLExprParser::parseColumn()
// {
//   SQLColumnDefinition_ptr column = createColumnDefinition();
//   column->setName(getName());
//   column->setDataType(parseDataType());

//   return parseColumnRest(column);
// }

SQLColumnDefinition_ptr SQLExprParser::parseColumn()
{
  return parseColumn(nullptr);
}

SQLColumnDefinition_ptr SQLExprParser::parseColumn(SQLObject_ptr parent)
{
  SQLColumnDefinition_ptr column = createColumnDefinition();
  column->setName(getName());

  Token_ptr token_ = lexer->token();
  if (token_->name->c_str() != Token::SET.name->c_str() //
      && token_->name->c_str() != Token::DROP.name->c_str() &&
      token_->name->c_str() != Token::PRIMARY.name->c_str() &&
      token_->name->c_str() != Token::RPAREN.name->c_str() &&
      token_->name->c_str() != Token::COMMA.name->c_str())
  {
    column->setDataType(parseDataType());
  }
  return parseColumnRest(column);
}

SQLColumnDefinition_ptr SQLExprParser::createColumnDefinition()
{
  SQLColumnDefinition_ptr column = SQLColumnDefinition_ptr(new SQLColumnDefinition());
  return column;
}

SQLColumnDefinition_ptr SQLExprParser::parseColumnRest(SQLColumnDefinition_ptr column)
{
  if (lexer->token()->name->c_str() == Token::DEFAULT.name->c_str())
  {
    lexer->nextToken();
    column->setDefaultExpr(bitOr());
    return parseColumnRest(column);
  }

  if (lexer->token()->name->c_str() == Token::NOT.name->c_str())
  {
    lexer->nextToken();
    accept(Token::XNULL);
    column->getConstraints()->push_back(SQLNotNullConstraint_ptr(new SQLNotNullConstraint()));
    return parseColumnRest(column);
  }

  if (lexer->token()->name->c_str() == Token::XNULL.name->c_str())
  {
    lexer->nextToken();
    column->setDefaultExpr(SQLNullExpr_ptr(new SQLNullExpr()));
    return parseColumnRest(column);
  }

  if (lexer->token()->name->c_str() == Token::PRIMARY.name->c_str())
  {
    lexer->nextToken();
    accept(Token::KEY);
    column->getConstraints()->push_back(SQLColumnPrimaryKey_ptr(new SQLColumnPrimaryKey()));
    return parseColumnRest(column);
  }

  if (lexer->token()->name->c_str() == Token::UNIQUE.name->c_str())
  {
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::KEY.name->c_str())
    {
      lexer->nextToken();
    }
    column->getConstraints()->push_back(SQLColumnPrimaryKey_ptr(new SQLColumnPrimaryKey()));
    return parseColumnRest(column);
  }

  if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str())
  {
    lexer->nextToken();

    SQLName_ptr name = getName();

    if (lexer->token()->name->c_str() == Token::PRIMARY.name->c_str())
    {
      lexer->nextToken();
      accept(Token::KEY);
      SQLColumnPrimaryKey_ptr pk = SQLColumnPrimaryKey_ptr(new SQLColumnPrimaryKey());
      pk->setName(name);
      column->getConstraints()->push_back(pk);
      return parseColumnRest(column);
    }

    if (lexer->token()->name->c_str() == Token::UNIQUE.name->c_str())
    {
      lexer->nextToken();
      SQLColumnUniqueKey_ptr uk = SQLColumnUniqueKey_ptr(new SQLColumnUniqueKey());
      uk->setName(name);
      column->getConstraints()->push_back(uk);
      return parseColumnRest(column);
    }

    if (lexer->token()->name->c_str() == Token::REFERENCES.name->c_str())
    {
      lexer->nextToken();
      SQLColumnReference_ptr ref = SQLColumnReference_ptr(new SQLColumnReference());
      ref->setName(name);
      ref->setTable(getName());
      accept(Token::LPAREN);
      getNames(ref->getColumns(), std::dynamic_pointer_cast<SQLObject>(ref));
      accept(Token::RPAREN);
      column->getConstraints()->push_back(ref);
      return parseColumnRest(column);
    }

    if (lexer->token()->name->c_str() == Token::NOT.name->c_str())
    {
      lexer->nextToken();
      accept(Token::XNULL);
      SQLNotNullConstraint_ptr notNull = SQLNotNullConstraint_ptr(new SQLNotNullConstraint());
      notNull->setName(name);
      column->getConstraints()->push_back(notNull);
      return parseColumnRest(column);
    }

    if (lexer->token()->name->c_str() == Token::CHECK.name->c_str())
    {
      SQLColumnCheck_ptr check = parseColumnCheck();
      check->setName(name);
      check->setParent(column);
      column->getConstraints()->push_back(check);
      return parseColumnRest(column);
    }

    if (lexer->token()->name->c_str() == Token::DEFAULT.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr expr = getExpr();
      column->setDefaultExpr(expr);
      return parseColumnRest(column);
    }

    // throw new ParserException(string_ptr ("TODO : ") + tokenStringList.at(lexer->token()->name->c_str()) + string_ptr (" ") + lexer->stringVal());
    throw new ParserException(make_string_ptr("TODO :  " + encode_util::UnicodeToUTF8(*lexer->stringVal())));
  }

  if (lexer->token()->name->c_str() == Token::CHECK.name->c_str())
  {
    SQLColumnCheck_ptr check = parseColumnCheck();
    column->getConstraints()->push_back(check);
    return parseColumnRest(column);
  }

  if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
  {
    lexer->nextToken();
    column->setComment(primary());
  }

  return column;
}

SQLColumnCheck_ptr SQLExprParser::parseColumnCheck()
{
  lexer->nextToken();
  SQLExpr_ptr expr = getExpr();
  SQLColumnCheck_ptr check = SQLColumnCheck_ptr(new SQLColumnCheck(expr));

  if (lexer->token()->name->c_str() == Token::DISABLE.name->c_str())
  {
    lexer->nextToken();
    check->setEnable(BOOL::FALSE);
  }
  else if (lexer->token()->name->c_str() == Token::ENABLE.name->c_str())
  {
    lexer->nextToken();
    check->setEnable(BOOL::TRUE);
  }
  return check;
}

SQLConstraint_ptr SQLExprParser::parsePrimaryKey()
{
  accept(Token::PRIMARY);
  accept(Token::KEY);

  SQLPrimaryKeyImpl_ptr pk = SQLPrimaryKeyImpl_ptr(new SQLPrimaryKeyImpl());
  accept(Token::LPAREN);
  // exprList(pk->getColumns());
  accept(Token::RPAREN);

  return pk;
}

SQLUnique_ptr SQLExprParser::parseUnique()
{
  accept(Token::UNIQUE);

  SQLUnique_ptr unique = SQLUnique_ptr(new SQLUnique());
  accept(Token::LPAREN);
  // exprList(unique->getColumns());
  accept(Token::RPAREN);

  return unique;
}

SQLAssignItem_ptr SQLExprParser::parseAssignItem()
{
  SQLAssignItem_ptr item = SQLAssignItem_ptr(new SQLAssignItem());

  SQLExpr_ptr var = primary();

  SQLIdentifierExpr_ptr v = std::dynamic_pointer_cast<SQLIdentifierExpr>(var);
  // if (var instanceof SQLIdentifierExpr) {
  if (v != 0)
  {
    // var = new SQLVariantRefExpr(((SQLIdentifierExpr) var).getName());
    var = SQLVariantRefExpr_ptr(new SQLVariantRefExpr(v->getName()));
  }
  item->setTarget(var);
  if (lexer->token()->name->c_str() == Token::COLONEQ.name->c_str())
  {
    lexer->nextToken();
  }
  else
  {
    accept(Token::EQ);
  }
  item->setValue(getExpr());

  return item;
}

void SQLExprParser::parseAssignItem(SQLAssignItem_list_ptr outList, SQLObject_ptr parent)
{
  accept(Token::LPAREN);
  for (;;)
  {
    SQLAssignItem_ptr item = this->parseAssignItem(BOOL::TRUE, parent);
    item->setParent(parent);
    outList->push_back(item);
    if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
    {
      lexer->nextToken();
      continue;
    }
    break;
  }
  accept(Token::RPAREN);
}

SQLAssignItem_ptr SQLExprParser::parseAssignItem(BOOL_ptr variant, SQLObject_ptr parent)
{
  SQLAssignItem_ptr item = SQLAssignItem_ptr(new SQLAssignItem());

  if (lexer->token()->name->c_str() == Token::DOT.name->c_str() &&
      dbType->name->c_str() == DbType::odps.name->c_str())
  {
    lexer->nextToken();
  }

  SQLExpr_ptr var;

  if (dbType->name->c_str() == DbType::odps.name->c_str() &&
      lexer->identifierEquals(L"NC_TO_BE_EXECUTED"))
  {
    lexer->nextToken(); // skip
  }

  if (lexer->identifierEquals(FnvHash::Constants::TBLPROPERTIES))
  {
    string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    var = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str() &&
        dbType->name->c_str() == DbType::odps.name->c_str())
    {
      SQLListExpr_ptr list = SQLListExpr_ptr(new SQLListExpr());
      this->exprList(list->getItems(), list);
      string_ptr tmp1 = make_string_ptr("tblproperties");
      item->setTarget(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp1)));
      item->setValue(list);
      return item;
    }
  }
  else
  {
    var = primary();
  }

  if (instanceof <SQLExpr, SQLPropertyExpr>(var) &&
                     lexer->token()->name->c_str() == Token::SUB.name->c_str() &&
                     dbType->name->c_str() == DbType::odps.name->c_str())
  {
    SQLPropertyExpr_ptr propertyExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(var);
    string_ptr name = make_string_ptr(*(propertyExpr->getName()) + '-');
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      name->append(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
    }

    propertyExpr->setName(name);

    var = this->primaryRest(propertyExpr);
  }

  if (instanceof <SQLExpr, SQLIdentifierExpr>(var) &&
                     dbType->name->c_str() == DbType::odps.name->c_str())
  {
    SQLIdentifierExpr_ptr identExpr = std::dynamic_pointer_cast<SQLIdentifierExpr>(var);
    if ((StringUtils::iequals(*identExpr->getName(), "et") ||
         StringUtils::iequals(*identExpr->getName(), "odps")) &&
        lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      SQLExpr_ptr expr = this->primary();
      string_ptr tmp = identExpr->getName();
      tmp->append(" ");
      tmp->append(expr->toString()->c_str());
      identExpr->setName(tmp);
    }
  }

  if (instanceof <SQLExpr, SQLPropertyExpr>(var) &&
                     dbType->name->c_str() == DbType::odps.name->c_str())
  {
    SQLPropertyExpr_ptr propertyExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(var);

    if (identifierEquals("DATEADD"))
    {
      string_ptr func = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
      {
        lexer->nextToken();
        accept(Token::RPAREN);
        func->append("()");
      }

      string_ptr name = make_string_ptr(*(propertyExpr->getName()) + *(func));
      propertyExpr->setName(name);
    }
    else if (StringUtils::iequals(*propertyExpr->getName(), "enab") && identifierEquals("le"))
    {
      string_ptr name = make_string_ptr((propertyExpr->getName())->append(encode_util::UnicodeToUTF8(*lexer->stringVal())));
      lexer->nextToken();
      propertyExpr->setName(name);
    }
    else if (StringUtils::iequals(*propertyExpr->getName(), "sq") && identifierEquals("l"))
    {
      string_ptr name = append_string_ptr(propertyExpr->getName(), make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
      lexer->nextToken();
      propertyExpr->setName(name);
    }
    else if (StringUtils::iequals(*propertyExpr->getName(), "s") && identifierEquals("ql"))
    {
      string_ptr name = append_string_ptr(propertyExpr->getName(), make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
      lexer->nextToken();
      propertyExpr->setName(name);
      var = this->primaryRest(propertyExpr);
    }
    else if (lexer->token()->name->c_str() == Token::BY.name->c_str())
    {
      string_ptr name = make_string_ptr(*(propertyExpr->getName()) + ' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      propertyExpr->setName(name);
      var = this->primaryRest(propertyExpr);
    }
  }

  if (variant && instanceof <SQLExpr, SQLIdentifierExpr>(var))
  {
    SQLIdentifierExpr_ptr ident = std::dynamic_pointer_cast<SQLIdentifierExpr>(var);
    if (lexer->identifierEquals(FnvHash::Constants::CLUSTER) &&
        ident->nameHashCode64() == FnvHash::Constants::RUNNING &&
        dbType->name->c_str() == DbType::odps.name->c_str())
    {
      string_ptr str = make_string_ptr(*(ident->getName()) + " " + encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
      ident->setName(str);
    }
    else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() &&
             dbType->name->c_str() == DbType::odps.name->c_str())
    {
      string_ptr tmp = make_string_ptr(*(ident->getName()) + ' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
      ident->setName(tmp);
      lexer->nextToken();
      while (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
      {
        string_ptr tmp1 = make_string_ptr(*(ident->getName()) + ' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
        ident->setName(tmp1);
        lexer->nextToken();
      }
    }

    string_ptr identName = ident->getName();
    if (identName->find('@') != -1 || identName->find('#') != -1 || identName->find(':') != -1 || identName->find(' ') != -1)
    {
      var = SQLVariantRefExpr_ptr(new SQLVariantRefExpr(identName));
    }
  }

  if (instanceof <SQLExpr, SQLMethodInvokeExpr>(var) &&
                     dbType->name->c_str() == DbType::odps.name->c_str())
  {
    SQLMethodInvokeExpr_ptr func = std::dynamic_pointer_cast<SQLMethodInvokeExpr>(var);

    SQLExpr_ptr owner = func->getOwner();
    if (owner != NULL)
    {
      item->setTarget(SQLPropertyExpr_ptr(new SQLPropertyExpr(owner, func->getMethodName())));
    }
    else
    {
      item->setTarget(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(func->getMethodName())));
    }

    SQLListExpr_ptr properties = SQLListExpr_ptr(new SQLListExpr());
    for (auto argument : *func->getArguments())
    {
      properties->addItem(argument);
    }

    item->setValue(properties);
    return item;
  }

  item->setTarget(var);

  if (lexer->token()->name->c_str() == Token::COLONEQ.name->c_str())
  {
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::XTRUE.name->c_str() || lexer->identifierEquals(FnvHash::Constants::XTRUE))
  {
    lexer->nextToken();
    item->setValue(SQLBooleanExpr_ptr(new SQLBooleanExpr(true)));
    return item;
  }
  else if (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();
    string_ptr tmp = make_string_ptr("ON");
    item->setValue(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp)));
    return item;
  }
  else if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str() ||
           lexer->token()->name->c_str() == Token::COMMA.name->c_str() ||
           lexer->token()->name->c_str() == Token::SET.name->c_str())
  {
    if (dbType->name->c_str() == DbType::odps.name->c_str() ||
        dbType->name->c_str() == DbType::hive.name->c_str())
    {
      return item;
    }
  }
  else
  {
    if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
    {
      // if (dbType == DbType::odps && (instanceof<SQLObject, SQLSetStatement>(parent )  || parent == NULL)) {
      //     lexer->nextTokenForSet();
      // } else {
      //     lexer->nextToken();
      // }
      if (lexer->token()->name->c_str() == Token::SEMI.name->c_str() &&
          dbType->name->c_str() == DbType::odps.name->c_str())
      {
        return item;
      }
    }
    else if (dbType->name->c_str() == DbType::db2.name->c_str())
    {
      // skip
    }
    else if (lexer->token()->name->c_str() == Token::QUES.name->c_str() ||
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() ||
             lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str() ||
             lexer->identifierEquals(L"utf8mb4"))
    {
      // skip
    }
    else if (lexer->token()->name->c_str() == Token::EQEQ.name->c_str() &&
             dbType->name->c_str() == DbType::odps.name->c_str())
    {
      lexer->nextToken();
    }
    else
    {
      accept(Token::EQ);
    }
  }

  if (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    item->setValue(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp)));
    lexer->nextToken();
  }
  else
  {
    if (lexer->token()->name->c_str() == Token::ALL.name->c_str())
    {
      string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      item->setValue(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp)));
      lexer->nextToken();
    }
    else
    {
      SQLExpr_ptr expr = getExpr();

      if (dbType->name->c_str() == DbType::odps.name->c_str())
      {
        while (lexer->token()->name->c_str() == Token::LITERAL_FLOAT.name->c_str() &&
               StringUtils::startWith(make_string_ptr(encode_util::UnicodeToUTF8(lexer->numberString())), make_string_ptr(".")))
        {
          if (instanceof <SQLExpr, SQLNumberExpr>(expr))
          {
            string_ptr numStr = (std::dynamic_pointer_cast<SQLNumberExpr>(expr))->getLiteral();
            numStr->append(encode_util::UnicodeToUTF8(lexer->numberString()));
            expr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(numStr));
            lexer->nextToken();
          }
          else if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
          {
            string_ptr ident = (std::dynamic_pointer_cast<SQLIdentifierExpr>(expr))->getName();
            ident->append(encode_util::UnicodeToUTF8(lexer->numberString()));
            expr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(ident));
            lexer->nextToken();
          }
          else
          {
            break;
          }
        }
      }

      if (lexer->token()->name->c_str() == Token::COLON.name->c_str())
      {
        if (dbType->name->c_str() == DbType::hive.name->c_str() ||
            dbType->name->c_str() == DbType::odps.name->c_str())
        {
          Lexer_SavePoint_ptr mark = lexer->mark();
          lexer->nextToken();
          string_ptr str = make_string_ptr(expr->toString()->c_str() + ':');
          str->append(encode_util::UnicodeToUTF8(lexer->numberString()));
          lexer->nextToken();
          expr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(str));
        }
      }

      // if (lexer->token()->name->c_str() == Token::COMMA
      //         && (DbType::postgresql == dbType
      //         || (DbType::odps == dbType && instanceof<SQLObject, SQLSetStatement>(parent ) ))) {
      //     SQLListExpr* listExpr = new SQLListExpr();
      //     listExpr->addItem(expr);
      //     expr->setParent(listExpr);
      //     do {
      //         lexer->nextToken();
      //         if (lexer->token()->name->c_str() == Token::SET && dbType == DbType::odps) {
      //             break;
      //         }
      //         SQLExpr_ptr  listItem = this->getExpr();
      //         listItem->setParent(listExpr);
      //         listExpr->addItem(listItem);
      //     } while (lexer->token()->name->c_str() == Token::COMMA);
      //     item->setValue(listExpr);
      // } else {
      //     item->setValue(expr);
      // }
    }
  }

  return item;
}

SQLCommentHint_list_ptr SQLExprParser::parseHints()
{
  SQLCommentHint_list_ptr hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
  parseHints(hints);
  return hints;
}

void SQLExprParser::parseHints(SQLCommentHint_list_ptr hints)
{
  while (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    string_ptr text = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    SQLCommentHint_ptr hint;

    if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::TDDLHint))) &&
        (StringUtils::startWith(text, make_string_ptr("+ TDDL")) ||
         StringUtils::startWith(text, make_string_ptr("+TDDL")) ||
         StringUtils::startWith(text, make_string_ptr("!TDDL")) ||
         StringUtils::startWith(text, make_string_ptr("TDDL"))))
    {
      hint = TDDLHint_ptr(new TDDLHint(text));
    }
    else
    {
      hint = SQLCommentHint_ptr(new SQLCommentHint(text));
    }

    if (lexer->commentCount > 0)
    {
      hint->addBeforeComment(lexer->comments);
    }

    hints->push_back(hint);
    lexer->nextToken();
  }
}

void SQLExprParser::parseHints(SQLHint_list_ptr hints)
{
  while (lexer->token()->name->c_str() == Token::HINT.name->c_str())
  {
    string_ptr text = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    SQLCommentHint_ptr hint;

    if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::TDDLHint))) &&
        (StringUtils::startWith(text, make_string_ptr("+ TDDL")) ||
         StringUtils::startWith(text, make_string_ptr("+TDDL")) ||
         StringUtils::startWith(text, make_string_ptr("!TDDL")) ||
         StringUtils::startWith(text, make_string_ptr("TDDL"))))
    {
      hint = TDDLHint_ptr(new TDDLHint(text));
    }
    else
    {
      hint = SQLCommentHint_ptr(new SQLCommentHint(text));
    }

    if (lexer->commentCount > 0)
    {
      hint->addBeforeComment(lexer->comments);
    }

    hints->push_back(hint);
    lexer->nextToken();
  }
}

SQLConstraint_ptr SQLExprParser::parseConstaint()
{
  SQLName_ptr name = NULL;

  if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str())
  {
    lexer->nextToken();
    name = getName();
  }

  SQLConstraint_ptr constraint;
  if (lexer->token()->name->c_str() == Token::PRIMARY.name->c_str())
  {

    constraint = parsePrimaryKey();
  }
  else if (lexer->token()->name->c_str() == Token::UNIQUE.name->c_str())
  {

    constraint = parseUnique();
  }
  else if (lexer->token()->name->c_str() == Token::FOREIGN.name->c_str())
  {

    constraint = parseForeignKey();
  }
  else if (lexer->token()->name->c_str() == Token::CHECK.name->c_str())
  {

    constraint = std::dynamic_pointer_cast<SQLConstraintImpl>(parseCheck());
  }
  else
  {

    // throw new ParserException(string_ptr ("TODO : ") + tokenStringList.at(lexer->token()->name->c_str()) + string_ptr (" ") + lexer->stringVal());
    throw new ParserException(make_string_ptr("TODO :  " + encode_util::UnicodeToUTF8(*lexer->stringVal())));
  }

  constraint->setName(name);

  return constraint;
}

SQLCheck_ptr SQLExprParser::parseCheck()
{
  accept(Token::CHECK);
  SQLCheck_ptr check = createCheck();
  accept(Token::LPAREN);
  check->setExpr(getExpr());
  accept(Token::RPAREN);
  return check;
}

SQLCheck_ptr SQLExprParser::createCheck()
{
  return SQLCheck_ptr(new SQLCheck());
}

SQLForeignKeyConstraint_ptr SQLExprParser::parseForeignKey()
{
  accept(Token::FOREIGN);
  accept(Token::KEY);

  SQLForeignKeyConstraint_ptr fk = createForeignKey();

  accept(Token::LPAREN);
  getNames(fk->getReferencingColumns());
  accept(Token::RPAREN);

  accept(Token::REFERENCES);

  fk->setReferencedTableName(getName());

  accept(Token::LPAREN);
  getNames(fk->getReferencedColumns());
  accept(Token::RPAREN);
  return fk;
}

SQLForeignKeyConstraint_ptr SQLExprParser::createForeignKey()
{
  return SQLForeignKeyConstraint_ptr(new SQLForeignKeyImpl());
}

SQLUpdateSetItem_ptr SQLExprParser::parseUpdateSetItem()
{
  SQLUpdateSetItem_ptr item = SQLUpdateSetItem_ptr(new SQLUpdateSetItem());

  if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
  {
    lexer->nextToken();
    SQLListExpr_ptr list = SQLListExpr_ptr(new SQLListExpr());
    this->exprList(list->getItems(), list);
    accept(Token::RPAREN);
    item->setColumn(list);
  }
  else
  {
    string_ptr identName;
    long hash;

    Token_ptr token = lexer->token();
    if (token->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      hash = lexer->hashLCase();
    }
    else if (token->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      identName = make_string_ptr('\'' + encode_util::UnicodeToUTF8(*lexer->stringVal()) + '\'');
      hash = 0;
    }
    else
    {
      identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      hash = 0;
    }
    lexer->nextTokenEq();
    SQLExpr_ptr expr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(identName, hash));
    while (lexer->token()->name->c_str() == Token::DOT.name->c_str())
    {
      lexer->nextToken();
      string_ptr propertyName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextTokenEq();
      expr = SQLPropertyExpr_ptr(new SQLPropertyExpr(expr, propertyName));
    }

    item->setColumn(expr);
  }

  if (lexer->token()->name->c_str() == Token::LBRACKET.name->c_str() &&
      dbType->name->c_str() == DbType::postgresql.name->c_str())
  {
    SQLExpr_ptr column = item->getColumn();
    column = this->primaryRest(column);
    item->setColumn(column);
  }

  if (lexer->token()->name->c_str() == Token::COLONEQ.name->c_str())
  {
    lexer->nextTokenValue();
  }
  else if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
  {
    lexer->nextTokenValue();
  }
  else
  {
    std::string tmp = "syntax error, expect EQ, actual ";
    tmp += lexer->token()->getName()->c_str();
    tmp += " ";
    tmp += encode_util::UnicodeToUTF8(lexer->info());
    throw new ParserException(make_string_ptr(tmp));
  }

  item->setValue(this->getExpr());
  return item;
}

SQLSelectItem_ptr SQLExprParser::parseSelectItem()
{
  SQLExpr_ptr expr;
  bool connectByRoot = false;
  Token_ptr token = lexer->token();
  int startPos = lexer->startPos;
  LOG_INFO << ": token name:" << lexer->token()->getName()->c_str();

  if (token->name->c_str() == Token::IDENTIFIER.name->c_str() &&
      !(lexer->hashLCase() == -5808529385363204345L &&
        lexer->charAt(lexer->pos()) == L'\'' &&
        dbType->name->c_str() == DbType::mysql.name->c_str()) // x'123' X'123'
  )
  {
    std::string ident_tmp = encode_util::UnicodeToUTF8(*lexer->stringVal());
    string_ptr ident = make_string_ptr(ident_tmp);
    LOG_INFO << ": ident:" << ident->c_str();
    long hash_lower = lexer->hashLCase();
    LOG_INFO << ": hash_lower:" << hash_lower;
    lexer->nextTokenComma();
    LOG_INFO << ": ident:" << ident->c_str();
    LOG_INFO << ": CHAR:" << FnvHash::Constants::CHAR;
    LOG_INFO << ": VARCHAR:" << FnvHash::Constants::VARCHAR;
    LOG_INFO << ": token name:" << lexer->token()->getName()->c_str();

    if (hash_lower == FnvHash::Constants::CONNECT_BY_ROOT)
    {
      LOG_INFO << ":";
      connectByRoot = (lexer->token()->name->c_str() != Token::LPAREN.name->c_str());
      if (connectByRoot)
      {
        string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        expr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
        lexer->nextToken();
      }
      else
      {
        expr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(ident));
      }
    }
    else if (lexer->identifierEquals(FnvHash::Constants::COLLATE) &&
             dbType->name->c_str() == DbType::mysql.name->c_str() &&
             lexer->stringVal()->at(0) != '`')
    {
      LOG_INFO << ":";
      lexer->nextToken();
      string_ptr collate = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();

      SQLBinaryOpExpr_ptr binaryExpr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(
          SQLIdentifierExpr_ptr(new SQLIdentifierExpr(ident)),
          SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::COLLATE)),
          SQLIdentifierExpr_ptr(new SQLIdentifierExpr(collate)),
          DbType_ptr(new DbType(&DbType::mysql))));

      expr = binaryExpr;
    }
    else if (lexer->identifierEquals(FnvHash::Constants::REGEXP) &&
             lexer->stringVal()->at(0) != '`' &&
             dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      LOG_INFO << ":";
      lexer->nextToken();
      SQLExpr_ptr rightExp = bitOr();

      SQLBinaryOpExpr_ptr binaryExpr = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(
          SQLIdentifierExpr_ptr(new SQLIdentifierExpr(ident)),
          SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::RegExp)),
          rightExp,
          DbType_ptr(new DbType(&(DbType::mysql)))));

      expr = binaryExpr;
      expr = relationalRest(expr);
    }
    else if (FnvHash::Constants::DATE == hash_lower &&
             lexer->stringVal()->at(0) != '`' &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str()) /*&&
             (SQLDateExpr::isSupport(dbType))) */
    {
      LOG_INFO << ":";
      string_ptr literal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();

      // SQLDateExpr* dateExpr = new SQLDateExpr();
      // dateExpr.setLiteral(literal);

      // expr = dateExpr;
    }
    else if (FnvHash::Constants::TIMESTAMP == hash_lower &&
             lexer->stringVal()->at(0) != '`' &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() &&
             !(dbType->name->c_str() == DbType::oracle.name->c_str()))
    {
      LOG_INFO << ":";
      string_ptr literal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();

      // SQLTimestampExpr* ts = new SQLTimestampExpr(literal);
      // expr = ts;

      if (lexer->identifierEquals(FnvHash::Constants::AT))
      {
        Lexer_SavePoint_ptr mark = lexer->mark();
        lexer->nextToken();

        string_ptr timeZone = NULL;
        if (lexer->identifierEquals(FnvHash::Constants::TIME))
        {
          lexer->nextToken();
          if (lexer->identifierEquals(FnvHash::Constants::ZONE))
          {
            lexer->nextToken();
            timeZone = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
            lexer->nextToken();
          }
        }
        if (timeZone->empty())
        {
          lexer->reset(mark);
        }
        else
        {
          // ts.setTimeZone(timeZone);
        }
      }
    }
    else if (FnvHash::Constants::DATETIME == hash_lower &&
             lexer->stringVal()->at(0) != '`' &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() &&
             !(dbType->name->c_str() == DbType::oracle.name->c_str()))
    {
      LOG_INFO << ":";
      string_ptr literal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();

      // SQLDateTimeExpr ts = new SQLDateTimeExpr(literal);
      // expr = ts;
    }
    else if (FnvHash::Constants::BOOLEAN == hash_lower &&
             lexer->stringVal()->at(0) != '`' &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() &&
             dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr literal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();

      // SQLBooleanExpr* ts = new SQLBooleanExpr(Boolean.valueOf(literal));
      // expr = ts;
    }
    else if ((FnvHash::Constants::CHAR == hash_lower ||
              FnvHash::Constants::VARCHAR == hash_lower) &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str() &&
             dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr literal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();

      SQLCharExpr_ptr charExpr = SQLCharExpr_ptr(new SQLCharExpr(literal));
      expr = charExpr;
    }
    else if (FnvHash::Constants::TIME == hash_lower &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr literal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();

      // expr = new SQLTimeExpr(literal);
    }
    else if (hash_lower == FnvHash::Constants::DECIMAL &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr decimal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      // expr = new SQLDecimalExpr(decimal);
      lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::REAL &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr decimal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      // expr = new SQLRealExpr(decimal);
      lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::DOUBLE &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr decimal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      // expr = new SQLDoubleExpr(decimal);
      lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::FLOAT &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr decimal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      // expr = new SQLFloatExpr(decimal);
      lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::BIGINT &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      if (StringUtils::startWith(strVal, make_string_ptr("--")))
      {
        strVal = make_string_ptr(strVal->substr(2));
      }
      // expr = new SQLBigIntExpr(strVal);
      lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::INTEGER &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr strVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      if (StringUtils::startWith(strVal, make_string_ptr("--")))
      {
        strVal = make_string_ptr(strVal->substr(2));
      }
      // SQLIntegerExpr* integerExpr = SQLIntegerExpr::ofIntOrLong(Long.parseLong(strVal));
      // integerExpr.setType("INTEGER");
      // expr = integerExpr;
      lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::SMALLINT &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr decimal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      // expr = new SQLSmallIntExpr(decimal);
      lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::TINYINT &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr decimal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      // expr = new SQLTinyIntExpr(decimal);
      lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::JSON &&
             lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr decimal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      // expr = new SQLJSONExpr(decimal);
      lexer->nextToken();
    }
    else if (hash_lower == FnvHash::Constants::TRY_CAST)
    {
      LOG_INFO << ":";
      accept(Token::LPAREN);
      SQLCastExpr_ptr cast = SQLCastExpr_ptr(new SQLCastExpr());
      cast->setTry(BOOL::TRUE);
      cast->setExpr(getExpr());
      accept(Token::AS);
      cast->setDataType(parseDataType(BOOL::FALSE));
      accept(Token::RPAREN);
      expr = cast;
    }
    else if (FnvHash::Constants::CURRENT_DATE == hash_lower &&
             ident->at(0) != '`' &&
             lexer->token()->name->c_str() != Token::LPAREN.name->c_str() &&
             (dbType->name->c_str() == DbType::mysql.name->c_str() ||
              dbType->name->c_str() == DbType::hive.name->c_str()))
    {
      LOG_INFO << ":";
      // expr = new SQLCurrentTimeExpr(SQLCurrentTimeExpr::Type::CURRENT_DATE);
    }
    else if (FnvHash::Constants::CURRENT_TIMESTAMP == hash_lower &&
             ident->at(0) != '`' &&
             lexer->token()->name->c_str() != Token::LPAREN.name->c_str() &&
             (dbType->name->c_str() == DbType::mysql.name->c_str() ||
              dbType->name->c_str() == DbType::hive.name->c_str()))
    {
      LOG_INFO << ":";
      // expr = new SQLCurrentTimeExpr(SQLCurrentTimeExpr::Type::CURRENT_TIMESTAMP);
    }
    else if (FnvHash::Constants::CURRENT_TIME == hash_lower &&
             ident->at(0) != '`' &&
             lexer->token()->name->c_str() != Token::LPAREN.name->c_str() &&
             (dbType->name->c_str() == DbType::mysql.name->c_str() ||
              dbType->name->c_str() == DbType::hive.name->c_str()))
    {
      LOG_INFO << ":";
      // expr = new SQLCurrentTimeExpr(SQLCurrentTimeExpr::Type::CURRENT_TIME);
    }
    else if (FnvHash::Constants::CURDATE == hash_lower &&
             ident->at(0) != '`' &&
             lexer->token()->name->c_str() != Token::LPAREN.name->c_str() &&
             (dbType->name->c_str() == DbType::mysql.name->c_str() ||
              dbType->name->c_str() == DbType::hive.name->c_str()))
    {
      LOG_INFO << ":";
      // expr = new SQLCurrentTimeExpr(SQLCurrentTimeExpr::Type::CURDATE);
    }
    else if (FnvHash::Constants::LOCALTIME == hash_lower &&
             ident->at(0) != '`' &&
             lexer->token()->name->c_str() != Token::LPAREN.name->c_str() &&
             (dbType->name->c_str() == DbType::mysql.name->c_str() ||
              dbType->name->c_str() == DbType::hive.name->c_str()))
    {
      LOG_INFO << ":";
      // expr = new SQLCurrentTimeExpr(SQLCurrentTimeExpr::Type::LOCALTIME);
    }
    else if (FnvHash::Constants::LOCALTIMESTAMP == hash_lower &&
             ident->at(0) != '`' &&
             lexer->token()->name->c_str() != Token::LPAREN.name->c_str() &&
             (dbType->name->c_str() == DbType::mysql.name->c_str() ||
              dbType->name->c_str() == DbType::hive.name->c_str()))
    {
      LOG_INFO << ":";
      // expr = new SQLCurrentTimeExpr(SQLCurrentTimeExpr::Type::LOCALTIMESTAMP);
    }
    else if (FnvHash::Constants::CURRENT_USER == hash_lower &&
             ident->at(0) != '`' &&
             lexer->token()->name->c_str() != Token::LPAREN.name->c_str() &&
             isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::EnableCurrentUserExpr))))
    {
      LOG_INFO << ":";
      // expr = new SQLCurrentUserExpr();
    }
    else if ((FnvHash::Constants::_LATIN1 == hash_lower) &&
             ident->at(0) != '`' &&
             dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr hexString;
      if (lexer->token()->name->c_str() == Token::LITERAL_HEX.name->c_str())
      {
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(lexer->hexString()));
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
      {
        hexString = make_string_ptr("");
      }
      else
      {
        acceptIdentifier("X");
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        accept(Token::LITERAL_CHARS);
      }

      if (hexString->empty())
      {
        string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        lexer->nextToken();

        string_ptr collate = make_string_ptr("");
        if (lexer->identifierEquals(FnvHash::Constants::COLLATE))
        {
          lexer->nextToken();
          collate = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
          if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
          {
            lexer->nextToken();
          }
          else
          {
            accept(Token::IDENTIFIER);
          }
        }

        // expr = new MySqlCharExpr(str, "_latin1", collate);
      }
      else
      {
        // expr = new MySqlCharExpr(hexString, "_latin1");
      }
    }
    else if ((FnvHash::Constants::_UTF8 == hash_lower ||
              FnvHash::Constants::_UTF8MB4 == hash_lower) &&
             ident->at(0) != '`' &&
             dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr hexString;
      if (lexer->token()->name->c_str() == Token::LITERAL_HEX.name->c_str())
      {
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(lexer->hexString()));
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
      {
        hexString = make_string_ptr("");
      }
      else
      {
        acceptIdentifier("X");
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        accept(Token::LITERAL_CHARS);
      }

      if (hexString->empty())
      {
        string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        lexer->nextToken();

        string_ptr collate = NULL;
        if (lexer->identifierEquals(FnvHash::Constants::COLLATE))
        {
          lexer->nextToken();
          collate = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
          if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
          {
            lexer->nextToken();
          }
          else
          {
            accept(Token::IDENTIFIER);
          }
        }

        // expr = new MySqlCharExpr(str, "_utf8", collate);
      }
      else
      {
        // expr = new SQLCharExpr(MySqlUtils.utf8(hexString));
      }
    }
    else if ((FnvHash::Constants::_UTF16 == hash_lower ||
              FnvHash::Constants::_UCS2 == hash_lower) &&
             ident->at(0) != '`' &&
             dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr hexString;
      if (lexer->token()->name->c_str() == Token::LITERAL_HEX.name->c_str())
      {
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(lexer->hexString()));
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
      {
        hexString = make_string_ptr("");
      }
      else
      {
        acceptIdentifier("X");
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        accept(Token::LITERAL_CHARS);
      }

      if (hexString->empty())
      {
        string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        // hexString = HexBin.encode(str.getBytes(MySqlUtils::ASCII));
        lexer->nextToken();
      }

      // expr = new MySqlCharExpr(hexString, "_utf16");
    }
    else if (FnvHash::Constants::_UTF32 == hash_lower &&
             ident->at(0) != '`' &&
             dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr hexString;
      if (lexer->token()->name->c_str() == Token::LITERAL_HEX.name->c_str())
      {
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(lexer->hexString()));
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
      {
        hexString = make_string_ptr("");
      }
      else
      {
        acceptIdentifier("X");
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        accept(Token::LITERAL_CHARS);
      }

      if (hexString->empty())
      {
        string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        lexer->nextToken();
        // expr = new MySqlCharExpr(str, "_utf32");
      }
      else
      {
        // expr = new SQLCharExpr(MySqlUtils.utf32(hexString));
      }
    }
    else if (FnvHash::Constants::_GBK == hash_lower &&
             ident->at(0) != '`' &&
             dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr hexString;
      if (lexer->token()->name->c_str() == Token::LITERAL_HEX.name->c_str())
      {
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(lexer->hexString()));
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
      {
        hexString = make_string_ptr("");
      }
      else
      {
        acceptIdentifier("X");
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        accept(Token::LITERAL_CHARS);
      }

      if (hexString->empty())
      {
        string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        lexer->nextToken();
        // expr = new MySqlCharExpr(str, "_gbk");
      }
      else
      {
        // expr = new SQLCharExpr(MySqlUtils.gbk(hexString));
      }
    }
    else if (FnvHash::Constants::_BIG5 == hash_lower &&
             ident->at(0) != '`' &&
             dbType->name->c_str() == DbType::mysql.name->c_str())
    {
      LOG_INFO << ":";
      string_ptr hexString;
      if (lexer->token()->name->c_str() == Token::LITERAL_HEX.name->c_str())
      {
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(lexer->hexString()));
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
      {
        hexString = make_string_ptr("");
      }
      else
      {
        acceptIdentifier("X");
        hexString = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        accept(Token::LITERAL_CHARS);
      }

      if (hexString->empty())
      {
        string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        lexer->nextToken();
        // expr = new MySqlCharExpr(str, "_big5");
      }
      else
      {
        // expr = new SQLCharExpr(MySqlUtils::big5(hexString));
      }
    }
    else
    {
      LOG_INFO << ": dbType:" << dbType->name->c_str();
      if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))))
      {
        LOG_INFO << "goto SQLUtils::normalize";
        ident = SQLUtils::normalize(ident, dbType);
      }
      LOG_INFO << "ident->length():" << ident->length();
      if (ident->at(0) == '"' && ident->at(ident->length() - 1) == '"')
      {
        LOG_INFO << "goto FnvHash::hashCode64";
        hash_lower = FnvHash::hashCode64(ident);
      }
      LOG_INFO << ": ident:" << ident->c_str() << ",hash_lower:" << hash_lower;
      SQLIdentifierExpr_ptr identifierExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(ident, hash_lower));
      if (lexer->keepSourceLocation)
      {
        lexer->computeRowAndColumn();
        identifierExpr->setSourceLine(lexer->posLine);
        identifierExpr->setSourceColumn(lexer->posColumn);
      }
      expr = identifierExpr;
    }

    Token_ptr token = lexer->token();
    LOG_INFO << ": token name:" << token->getName()->c_str();
    if (*token == Token::DOT)
    {
      lexer->nextTokenIdent();
      string_ptr name;
      long name_hash_lower;

      if (lexer->token()->name->c_str() == Token::STAR.name->c_str())
      {
        name = make_string_ptr("*");
        name_hash_lower = FnvHash::Constants::STAR;
      }
      else
      {
        name = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        name_hash_lower = lexer->hashLCase();
      }

      lexer->nextTokenComma();

      token = lexer->token();
      if (*token == Token::LPAREN)
      {
        bool aggregate = hash_lower == FnvHash::Constants::WMSYS && name_hash_lower == FnvHash::Constants::WM_CONCAT;
        expr = methodRest(expr, name, aggregate);
        token = lexer->token();
      }
      else
      {
        if (name_hash_lower == FnvHash::Constants::NEXTVAL)
        {
          // expr = new SQLSequenceExpr((SQLIdentifierExpr)expr, SQLSequenceExpr.Function.NextVal);
        }
        else if (name_hash_lower == FnvHash::Constants::CURRVAL)
        {
          // expr = new SQLSequenceExpr((SQLIdentifierExpr)expr, SQLSequenceExpr.Function.CurrVal);
        }
        else if (name_hash_lower == FnvHash::Constants::PREVVAL)
        {
          // expr = new SQLSequenceExpr((SQLIdentifierExpr)expr, SQLSequenceExpr.Function.PrevVal);
        }
        else
        {
          if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))))
          {
            name = SQLUtils::normalize(name, dbType);
          }
          if (name->at(0) == '"')
          {
            name_hash_lower = FnvHash::hashCode64(name);
          }
          // expr = new SQLPropertyExpr(expr, name, name_hash_lower);
        }
      }
    }

    if (*token == Token::COMMA)
    {
      string_ptr tmp = make_string_ptr("");
      return SQLSelectItem_ptr(new SQLSelectItem(expr, tmp, connectByRoot));
    }

    if (*token == Token::AS)
    {
      lexer->nextTokenAlias();
      string_ptr as_ = NULL;
      if (lexer->token()->name->c_str() != Token::COMMA.name->c_str() && lexer->token()->name->c_str() != Token::FROM.name->c_str())
      {
        as_ = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))) && as_->length() > 1)
        {
          as_ = StringUtils::removeNameQuotes(as_);
        }

        lexer->nextTokenComma();

        if (lexer->token()->name->c_str() == Token::DOT.name->c_str())
        {
          lexer->nextToken();
          as_ = make_string_ptr(*as_ + '.' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
          lexer->nextToken();
        }
      }

      return SQLSelectItem_ptr(new SQLSelectItem(expr, as_, connectByRoot));
    }

    if (*token == Token::LITERAL_ALIAS)
    {
      string_ptr as_ = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))) && as_->length() > 1)
      {
        as_ = StringUtils::removeNameQuotes(as_);
      }
      lexer->nextTokenComma();
      return SQLSelectItem_ptr(new SQLSelectItem(expr, as_, connectByRoot));
    }

    if (*token == Token::IDENTIFIER &&
        hash_lower != FnvHash::Constants::CURRENT)
    {
      string_ptr as_;
      if (lexer->hashLCase() == FnvHash::Constants::FORCE &&
          DbType::mysql.name->c_str() == dbType->name->c_str())
      {
        string_ptr force = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));

        Lexer_SavePoint_ptr savePoint = lexer->mark();
        lexer->nextToken();

        if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str())
        {
          lexer->reset(savePoint);
          as_ = make_string_ptr("");
        }
        else
        {
          as_ = force;
          if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))) && as_->length() > 1)
          {
            as_ = StringUtils::removeNameQuotes(as_);
          }
          lexer->nextTokenComma();
        }
      }
      else if (lexer->hashLCase() == FnvHash::Constants::SOUNDS &&
               DbType::mysql.name->c_str() == dbType->name->c_str())
      {
        string_ptr sounds = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));

        Lexer_SavePoint_ptr savePoint = lexer->mark();
        lexer->nextToken();

        if (lexer->token()->name->c_str() == Token::LIKE.name->c_str())
        {
          lexer->reset(savePoint);
          expr = exprRest(expr);
          as_ = (as());
        }
        else
        {
          as_ = sounds;
          if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))) && as_->length() > 1)
          {
            as_ = StringUtils::removeNameQuotes(as_);
          }
          lexer->nextTokenComma();
        }
      }
      else if (lexer->hashLCase() == FnvHash::Constants::COLLATE &&
               lexer->stringVal()->at(0) != '`' &&
               DbType::mysql.name->c_str() == dbType->name->c_str())
      {
        expr = primaryRest(expr);
        as_ = as();
      }
      else if (lexer->hashLCase() == FnvHash::Constants::REGEXP &&
               lexer->stringVal()->at(0) != '`' &&
               DbType::mysql.name->c_str() == dbType->name->c_str())
      {
        expr = exprRest(expr);
        as_ = as();
      }
      else
      {
        as_ = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        if (isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::IgnoreNameQuotes))) &&
            as_->length() > 1)
        {
          as_ = StringUtils::removeNameQuotes(as_);
        }
        lexer->nextTokenComma();
      }
      return SQLSelectItem_ptr(new SQLSelectItem(expr, as_, connectByRoot));
    }

    if (*token == Token::LPAREN)
    {
      if (dbType->name->c_str() == DbType::mysql.name->c_str())
      {
        lexer->nextTokenValue();
      }
      else
      {
        lexer->nextToken();
      }
      expr = this->methodRest(expr, BOOL::FALSE);
    }
    else
    {
      LOG_INFO << ":";
      expr = this->primaryRest(expr);
    }
    LOG_INFO << ":";
    expr = this->exprRest(expr);
  }
  else if (token->name->c_str() == Token::STAR.name->c_str())
  {
    LOG_INFO << ":";
    expr = SQLAllColumnExpr_ptr(new SQLAllColumnExpr());
    lexer->nextToken();
    return SQLSelectItem_ptr(new SQLSelectItem(expr, (string_ptr)NULL, connectByRoot));
  }
  else if (token->name->c_str() == Token::DO.name->c_str() || token->name->c_str() == Token::JOIN.name->c_str() || token->name->c_str() == Token::TABLESPACE.name->c_str())
  {
    LOG_INFO << ":";
    expr = SQLName_ptr(this->getName());
    expr = this->exprRest(expr);
  }
  else
  {
    LOG_INFO << ": token name:" << lexer->token()->getName()->c_str();
    if (lexer->token()->name->c_str() == Token::DISTINCT.name->c_str() &&
        dbType->name->c_str() == DbType::elastic_search.name->c_str())
    {
      lexer->nextToken();
    }

    while (lexer->token()->name->c_str() == Token::HINT.name->c_str())
    {
      lexer->nextToken();
    }

    expr = getExpr();
  }

  LOG_INFO << ": token name:" << lexer->token()->getName()->c_str();
  string_ptr alias_;
  string_list_ptr aliasList = std::make_shared<std::list<string_ptr>>();
  if (lexer->token()->name->c_str() == Token::FULL.name->c_str() ||
      lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str())
  {
    LOG_INFO << ":";
    alias_ = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::AS.name->c_str())
  {
    LOG_INFO << ":";
    lexer->nextTokenAlias();
    if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str())
    {
      alias_ = make_string_ptr('"' + encode_util::UnicodeToUTF8(*lexer->stringVal()) + '"');
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      // aliasList = new ArrayList<string_ptr >();

      for (;;)
      {
        string_ptr stringVal = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        lexer->nextToken();

        aliasList->push_back(stringVal);

        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          continue;
        }
        break;
      }
      accept(Token::RPAREN);

      alias_ = make_string_ptr("");
    }
    else
    {
      alias_ = (alias());
    }
  }
  else if (lexer->token()->name->c_str() == Token::XEOF.name->c_str())
  {
    LOG_INFO << ":";
    alias_ = make_string_ptr("");
  }
  else
  {
    LOG_INFO << ":";
    alias_ = as();
  }

  LOG_INFO << ": alias_:" << alias_->c_str();
  if (alias_->empty() &&
      isEnabled(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::SelectItemGenerateAlias))) &&
      (!(instanceof <SQLExpr, SQLName>(expr))) &&
      !(instanceof <SQLExpr, SQLNumericLiteralExpr>(expr)) &&
      !(instanceof <SQLExpr, SQLCharExpr>(expr)) &&
      !(instanceof <SQLExpr, SQLNullExpr>(expr)) &&
      !(instanceof <SQLExpr, SQLBooleanExpr>(expr)))
  {
    LOG_INFO << ":";
    alias_ = make_string_ptr(encode_util::UnicodeToUTF8(lexer->subString(startPos, lexer->startPos - startPos)));

    if (!lexer->comments->empty())
    {
      std::list<wstring_ptr>::iterator it = lexer->comments->begin();
      for (int i = lexer->comments->size() - 1; i >= 0; i--)
      {
        std::advance(it, i);
        wstring_ptr comment = (*it);
        int p = alias_->find_last_of(encode_util::UnicodeToUTF8(*comment));
        if (p >= 0)
        {
          alias_ = make_string_ptr(alias_->substr(0, p - 1));
        }
      }
    }

    // alias_ = CharTypes.trim(alias_);
    std::string tmp = alias_->c_str();
    alias_ = make_string_ptr(StringUtils::trim(tmp));

    LOG_INFO << ":";
    if (alias_->length() > 0)
    {
      BOOL_ptr specialChar = BOOL::FALSE;
      for (int i = 0; i < alias_->length(); ++i)
      {
        char ch = alias_->at(i);

        if (dbType->name->c_str() == DbType::mysql.name->c_str())
        {
          if (ch == '`')
          {
            specialChar = BOOL::TRUE;
            break;
          }
        }
        else if (!CharTypes::isIdentifierChar(ch))
        {
          specialChar = BOOL::TRUE;
          break;
        }
      }
      if (specialChar)
      {
        if (dbType->name->c_str() == DbType::mysql.name->c_str())
        {
          // alias_ = alias_.replaceAll("`", "``");
          // boost::replace_all(*alias_, "`", "``");
          alias_ = StringUtils::replaceAll(alias_, make_string_ptr("`"), make_string_ptr("``"));
          alias_ = make_string_ptr('`' + *alias_ + '`');
        }
        else
        {
          // alias_ = alias_.replaceAll("\"", "\\\"");
          // boost::replace_all(*alias_, "\"", "\\\"");
          alias_ = StringUtils::replaceAll(alias_, make_string_ptr("\""), make_string_ptr("\\\""));
        }
      }
    }
  }

  SQLSelectItem_ptr selectItem;
  if (!aliasList->empty())
  {
    LOG_INFO << ":";
    selectItem = SQLSelectItem_ptr(new SQLSelectItem(expr, aliasList, connectByRoot));
  }
  else
  {
    LOG_INFO << ":";
    selectItem = SQLSelectItem_ptr(new SQLSelectItem(expr, alias_, connectByRoot));
  }
  LOG_INFO << ":";
  if (lexer->token()->name->c_str() == Token::HINT.name->c_str() &&
      !lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(SQLParserFeature::StrictForWall.mask, SQLParserFeature::StrictForWall.name))))
  {
    LOG_INFO << ":";
    string_ptr comment = make_string_ptr("/*" + encode_util::UnicodeToUTF8(*lexer->stringVal()) + "*/");
    selectItem->addAfterComment(comment);
    lexer->nextToken();
  }

  return selectItem;
}

SQLDataType_ptr SQLExprParser::parseDataType()
{
  return parseDataType(BOOL::TRUE);

  // if (lexer->token()->name->c_str() == Token::DEFAULT || lexer->token()->name->c_str() == Token::NOT || lexer->token()->name->c_str() == Token::XNULL) {
  // 	return NULL;
  // }

  // SQLName_ptr typeExpr = getName();
  // string_ptr  typeName = typeExpr->toString();

  // if (isCharType(typeName)) {

  // 	SQLCharacterDataType_ptr charType = new SQLCharacterDataType(typeName);

  // 	if (lexer->token()->name->c_str() == Token::LPAREN) {
  // 		lexer->nextToken();
  // 		SQLExpr_ptr  arg = getExpr();
  // 		arg->setParent(charType);
  // 		charType->getArguments().push_back(arg);
  // 		accept(Token::RPAREN);
  // 	}

  // 	return parseCharTypeRest(charType);
  // }

  // if (StringUtils::iequals(string_ptr ("character"), typeName) && StringUtils::iequals(string_ptr  ("varying"), lexer->getStringVal()) )
  // {
  // 	typeName += ' ' + lexer->getStringVal();
  // 	lexer->nextToken();
  // }

  // //if ("character".equalsIgnoreCase(typeName) && "varying".equalsIgnoreCase(lexer->getStringVal())) {
  // //}

  // SQLDataType_ptr dataType = new SQLDataTypeImpl(typeName);
  // return parseDataTypeRest(dataType);
}

SQLDataType_ptr SQLExprParser::parseDataType(BOOL_ptr restrict)
{
  Token_ptr token = lexer->token();
  if (*token == Token::DEFAULT || *token == Token::NOT || *token == Token::XNULL)
  {
    return NULL;
  }

  if (lexer->identifierEquals(FnvHash::Constants::ARRAY))
  {
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      // lexer->nextToken();
      // SQLArrayDataType *array = new SQLArrayDataType(NULL, dbType);
      // this->exprList(array->getArguments(), array);
      // accept(Token::RPAREN);
      // return array;
    }

    accept(Token::LT);
    SQLDataType_ptr itemType = parseDataType();

    if (lexer->token()->name->c_str() == Token::GTGT.name->c_str())
    {
      lexer->token_ = Token_ptr(new Token(&Token::GT));
    }
    else
    {
      accept(Token::GT);
    }

    // SQLArrayDataType *array = new SQLArrayDataType(itemType, dbType);

    // if (lexer->token()->name->c_str() == Token::LPAREN)
    // {
    //   lexer->nextToken();
    //   this->exprList(array.getArguments(), array);
    //   accept(Token::RPAREN);
    // }

    // return array;
  }

  if (lexer->identifierEquals(FnvHash::Constants::MAP))
  {
    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    { // presto
      lexer->nextToken();
      SQLDataType_ptr keyType = parseDataType();
      accept(Token::COMMA);
      SQLDataType_ptr valueType = parseDataType();
      accept(Token::RPAREN);
      // return new SQLMapDataType(keyType, valueType, dbType);
    }

    accept(Token::LT);

    SQLDataType_ptr keyType = parseDataType();
    accept(Token::COMMA);
    SQLDataType_ptr valueType = parseDataType();
    if (lexer->token()->name->c_str() == Token::GTGT.name->c_str())
    {
      lexer->token_ = Token_ptr(new Token(&Token::GT));
    }
    else
    {
      accept(Token::GT);
    }

    // return new SQLMapDataType(keyType, valueType, dbType);
  }

  if (lexer->identifierEquals(FnvHash::Constants::STRUCT))
  {
    lexer->nextToken();

    // SQLStructDataType *struct_ = new SQLStructDataType(dbType);
    accept(Token::LT);
    for (;;)
    {
      SQLName_ptr name;
      if (lexer->token()->name->c_str() == Token::GROUP.name->c_str() ||
          lexer->token()->name->c_str() == Token::ORDER.name->c_str() ||
          lexer->token()->name->c_str() == Token::FROM.name->c_str() ||
          lexer->token()->name->c_str() == Token::TO.name->c_str())
      {
        string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        name = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
        lexer->nextToken();
      }
      else
      {
        name = this->getName();
      }

      accept(Token::COLON);
      SQLDataType_ptr dataType = this->parseDataType();
      // SQLStructDataType.Field field = struct_.addField(name, dataType);

      if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
      {
        lexer->nextToken();
        SQLCharExpr_ptr chars = std::dynamic_pointer_cast<SQLCharExpr>(this->primary());
        // field.setComment(chars.getText());
      }

      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }
      break;
    }
    if (lexer->token()->name->c_str() == Token::GTGT.name->c_str())
    {
      lexer->token_ = Token_ptr(new Token(&Token::GT));
    }
    else
    {
      accept(Token::GT);
    }
    // return struct_;
  }
  else if (lexer->token()->name->c_str() == Token::TABLE.name->c_str())
  {
    lexer->nextToken();
    // SQLTableDataType *table = new SQLTableDataType();
    accept(Token::LPAREN);
    for (;;)
    {
      SQLColumnDefinition_ptr column;
      if (lexer->token()->name->c_str() == Token::STAR.name->c_str())
      {
        lexer->nextToken();
        column = SQLColumnDefinition_ptr(new SQLColumnDefinition());
        column->setName(make_string_ptr("*"));
        accept(Token::ANY);
      }
      else
      {
        column = this->parseColumn();
      }
      // column->setParent(table);
      // table->getColumns().push_back(column);
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }
      break;
    }
    accept(Token::RPAREN);
    // return table;
  }
  else if (lexer->identifierEquals(FnvHash::Constants::ROW) ||
           lexer->token()->name->c_str() == Token::ROW.name->c_str())
  {
    lexer->nextToken();
    // return parseSqlRowDataType();
  }
  else if (lexer->identifierEquals(FnvHash::Constants::NESTED) &&
           dbType->name->c_str() == DbType::clickhouse.name->c_str())
  {
    lexer->nextToken();
    accept(Token::LPAREN);

    // SQLStructDataType *struct_ = new SQLStructDataType(dbType);

    for (;;)
    {
      SQLName_ptr name;
      if (lexer->token()->name->c_str() == Token::GROUP.name->c_str() ||
          lexer->token()->name->c_str() == Token::ORDER.name->c_str() ||
          lexer->token()->name->c_str() == Token::FROM.name->c_str() ||
          lexer->token()->name->c_str() == Token::TO.name->c_str())
      {
        string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        name = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
        lexer->nextToken();
      }
      else
      {
        name = this->getName();
      }

      SQLDataType_ptr dataType = this->parseDataType();
      // SQLStructDataType.Field field = struct_.addField(name, dataType);

      if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
      {
        lexer->nextToken();
        SQLCharExpr_ptr chars = std::dynamic_pointer_cast<SQLCharExpr>(this->primary());
        // field.setComment(chars.getText());
      }

      // if (lexer->token()->name->c_str() == Token::COMMA)
      {
        lexer->nextToken();
        continue;
      }
      break;
    }

    accept(Token::RPAREN);

    // return struct_;
  }

  if (lexer->identifierEquals(FnvHash::Constants::UNIONTYPE))
  {
    lexer->nextToken();
    accept(Token::LT);

    // SQLUnionDataType *unionType = new SQLUnionDataType();
    for (;;)
    {
      SQLDataType_ptr item = this->parseDataType();
      // unionType.add(item);
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }

      break;
    }
    accept(Token::GT);
    // return unionType;
  }

  if (lexer->identifierEquals(FnvHash::Constants::GENERATED) || lexer->identifierEquals(FnvHash::Constants::RENAME))
  {
    return NULL;
  }

  SQLName_ptr typeExpr = getName();
  long typeNameHashCode = typeExpr->nameHashCode64();
  string_ptr typeName = typeExpr->toString();

  if (typeNameHashCode == FnvHash::Constants::LONG &&
      lexer->identifierEquals(FnvHash::Constants::BYTE) &&
      DbType::mysql.name->c_str() == dbType->name->c_str())
  {
    typeName->append(' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
  }
  else if (typeNameHashCode == FnvHash::Constants::DOUBLE)
  {
    if (DbType::postgresql.name->c_str() == dbType->name->c_str())
    {
      typeName->append(' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
             lexer->identifierEquals(FnvHash::Constants::PRECISION))
    {
      typeName->append(' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
    }
  }

  if (typeNameHashCode == FnvHash::Constants::UNSIGNED)
  {
    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      typeName->append(' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
    }
  }
  else if (typeNameHashCode == FnvHash::Constants::SIGNED)
  {
    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      typeName->append(' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
    }
  }
  else if (isCharType(typeNameHashCode))
  {
    SQLCharacterDataType_ptr charType = SQLCharacterDataType_ptr(new SQLCharacterDataType(typeName));

    // for ads
    if (lexer->token()->name->c_str() == Token::LBRACKET.name->c_str())
    {
      // SQLArrayDataType *arrayDataType = new SQLArrayDataType(charType, dbType);
      lexer->nextToken();
      accept(Token::RBRACKET);
      // arrayDataType.putAttribute("ads.arrayDataType", Boolean.TRUE);
      // return arrayDataType;
    }

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      if (typeNameHashCode == FnvHash::Constants::ENUM)
      {
        exprList(charType->getArguments(), charType);
      }
      else
      {
        SQLExpr_ptr arg = this->getExpr();
        // arg->setParent(charType);
        charType->addArgument(arg);
      }
      accept(Token::RPAREN);
    }

    charType = std::dynamic_pointer_cast<SQLCharacterDataType>(SQLDataType_ptr(parseCharTypeRest(charType)));

    if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
    {
      SQLCommentHint_list_ptr hints = this->parseHints();
      charType->setHints(hints);
    }

    if (lexer->identifierEquals(FnvHash::Constants::ARRAY))
    {
      return parseDataTypeRest(charType);
    }
    else if (lexer->token()->name->c_str() == Token::LBRACKET.name->c_str())
    {
      return parseDataTypeRest(charType);
    }

    return charType;
  }

  if (StringUtils::iequals("national", *typeName) &&
      (lexer->identifierEquals(FnvHash::Constants::CHAR) ||
       lexer->identifierEquals(FnvHash::Constants::VARCHAR)))
  {
    typeName->append(' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();

    SQLCharacterDataType_ptr charType = SQLCharacterDataType_ptr(new SQLCharacterDataType(typeName));

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
      SQLExpr_ptr arg = this->getExpr();
      // arg->setParent(charType);
      charType->addArgument(arg);
      accept(Token::RPAREN);
    }

    charType = std::dynamic_pointer_cast<SQLCharacterDataType>(parseCharTypeRest(charType));

    if (lexer->token()->name->c_str() == Token::HINT.name->c_str())
    {
      SQLCommentHint_list_ptr hints = this->parseHints();
      charType->setHints(hints);
    }

    if (lexer->identifierEquals(FnvHash::Constants::ARRAY))
    {
      return parseDataTypeRest(charType);
    }

    return charType;
  }

  if (StringUtils::iequals("character", *typeName) &&
      StringUtils::iequals("varying", encode_util::UnicodeToUTF8(*lexer->stringVal())))
  {
    typeName->append(' ' + encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == Token::LT.name->c_str() &&
      dbType->name->c_str() == DbType::odps.name->c_str())
  {
    lexer->nextToken();
    typeName->append("<");
    for (;;)
    {
      SQLDataType_ptr itemType = this->parseDataType();
      typeName->append(itemType->toString()->c_str());
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        typeName->append(", ");
        continue;
      }
      else
      {
        break;
      }
    }
    accept(Token::GT);
    typeName->append(">");
  }

  SQLDataType_ptr dataType = SQLDataType_ptr(new SQLDataTypeImpl(typeName));
  dataType->setDbType(dbType);

  // for ads
  if (lexer->token()->name->c_str() == Token::LBRACKET.name->c_str())
  {
    // dataType = new SQLArrayDataType(dataType, dbType);
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str())
    {
      SQLExpr_ptr arg = this->getExpr();
      // arg->setParent(dataType);
      // dataType->getArguments().push_back(arg);
    }
    accept(Token::RBRACKET);
    // dataType->putAttribute("ads.arrayDataType", Boolean::TRUE);
  }

  return parseDataTypeRest(dataType);
}

void SQLExprParser::parseQueryPlanHint(SQLExpr_ptr expr)
{
  if (lexer->token()->name->c_str() == Token::HINT.name->c_str() &&
      (instanceof <SQLExpr, SQLInListExpr>(expr) || instanceof <SQLExpr, SQLBinaryOpExpr>(expr) || instanceof <SQLExpr, SQLInSubQueryExpr>(expr) || instanceof <SQLExpr, SQLExistsExpr>(expr) || instanceof <SQLExpr, SQLNotExpr>(expr) || instanceof <SQLExpr, SQLBetweenExpr>(expr)))
  {
    string_ptr text = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    std::string tmp = text->c_str();
    text = make_string_ptr(StringUtils::trim(tmp));

    //   Lexer_ptr hintLex = SQLParserUtils::createLexer(text, dbType);
    //   hintLex->nextToken();

    //   // 防止SQL注入
    //   if (hintLex->token() == Token::PLUS)
    //   {
    //     if (instanceof <SQLExpr, SQLBinaryOpExpr>(expr))
    //     {
    //       SQLBinaryOpExpr *binaryOpExpr = dynamic_cast<SQLBinaryOpExpr *>(expr);

    //       SQLBinaryOperator *operator_ = binaryOpExpr->getOperator();

    //       if (*operator_ == SQLBinaryOperator::BooleanAnd || *operator_ == SQLBinaryOperator::BooleanOr)
    //       {
    //         if (binaryOpExpr->isParenthesized())
    //         {
    //           // binaryOpExpr->setHint(new SQLCommentHint(text));
    //         }
    //         else
    //         {
    //           SQLExpr_ptr  right = binaryOpExpr->getRight();
    //           if (instanceof <SQLExpr, SQLBinaryOpExpr>(right) || instanceof <SQLExpr, SQLBetweenExpr>(right))
    //           {
    //             (dynamic_cast<SQLExprImpl *>(right))->setHint(new SQLCommentHint(text));
    //           }
    //         }
    //       }
    //       else
    //       {
    //         // binaryOpExpr->setHint(new SQLCommentHint(text));
    //       }
    //     }
    //     else if (instanceof <SQLExpr, SQLObjectImpl>(expr))
    //     {
    //       (dynamic_cast<SQLExprImpl *>(expr))->setHint(new SQLCommentHint(text));
    //     }
    //     else
    //     {
    //       throw new ParserException("TODO : " + lexer->info());
    //     }
    //     this->lexer->nextToken();
    //   }
  }
}

SQLExpr_ptr SQLExprParser::parseAny()
{
  SQLExpr_ptr sqlExpr;
  lexer->nextToken();
  if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    accept(Token::LPAREN);

    if (lexer->token()->name->c_str() == Token::ARRAY.name->c_str() || lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
    {
      SQLExpr_ptr expr = this->getExpr();
      string_ptr tmp = make_string_ptr("ANY");
      SQLMethodInvokeExpr_ptr methodInvokeExpr = SQLMethodInvokeExpr_ptr(new SQLMethodInvokeExpr(tmp));
      methodInvokeExpr->addArgument(expr);
      accept(Token::RPAREN);
      return methodInvokeExpr;
    }

    SQLSelect_ptr anySubQuery = createSelectParser()->select();
    SQLAnyExpr_ptr anyExpr = SQLAnyExpr_ptr(new SQLAnyExpr(anySubQuery));
    accept(Token::RPAREN);

    sqlExpr = anyExpr;
  }
  else
  {
    string_ptr tmp = make_string_ptr("ANY");
    sqlExpr = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp));
  }
  return sqlExpr;
}

SQLExpr_ptr SQLExprParser::parseSome()
{
  SQLExpr_ptr sqlExpr;

  string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
  lexer->nextToken();
  if (lexer->token()->name->c_str() != Token::LPAREN.name->c_str())
  {
    return SQLIdentifierExpr_ptr(new SQLIdentifierExpr(str));
  }
  lexer->nextToken();

  SQLSomeExpr_ptr someExpr = SQLSomeExpr_ptr(new SQLSomeExpr());
  SQLSelect_ptr someSubQuery = createSelectParser()->select();
  someExpr->setSubQuery(someSubQuery);
  accept(Token::RPAREN);

  someSubQuery->setParent(someExpr);

  sqlExpr = someExpr;
  return sqlExpr;
}

SQLExpr_ptr SQLExprParser::parseAll()
{
  SQLExpr_ptr sqlExpr;
  string_ptr str = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
  lexer->nextToken();
  if (lexer->token()->name->c_str() == Token::DOT.name->c_str() ||
      lexer->token()->name->c_str() == Token::SLASH.name->c_str() ||
      lexer->token()->name->c_str() == Token::EQ.name->c_str() ||
      lexer->token()->name->c_str() == Token::GT.name->c_str() ||
      lexer->token()->name->c_str() == Token::GTEQ.name->c_str() ||
      lexer->token()->name->c_str() == Token::LT.name->c_str() ||
      lexer->token()->name->c_str() == Token::LTEQ.name->c_str() ||
      lexer->token()->name->c_str() == Token::STAR.name->c_str() ||
      lexer->token()->name->c_str() == Token::DIV.name->c_str())
  {
    return primaryRest(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(str)));
  }
  else if (lexer->token()->name->c_str() == Token::COMMA.name->c_str() ||
           lexer->token()->name->c_str() == Token::PLUS.name->c_str() ||
           lexer->token()->name->c_str() == Token::SUB.name->c_str() ||
           lexer->token()->name->c_str() == Token::RPAREN.name->c_str() ||
           lexer->token()->name->c_str() == Token::WHERE.name->c_str() ||
           lexer->token()->name->c_str() == Token::GROUP.name->c_str() ||
           lexer->token()->name->c_str() == Token::SEMI.name->c_str() ||
           lexer->token()->name->c_str() == Token::AS.name->c_str() ||
           lexer->token()->name->c_str() == Token::FROM.name->c_str())
  {
    return SQLIdentifierExpr_ptr(new SQLIdentifierExpr(str));
  }
  else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
  {
    if (dbType->name->c_str() == DbType::odps.name->c_str())
    {
      return SQLIdentifierExpr_ptr(new SQLIdentifierExpr(str));
    }
  }

  SQLAllExpr_ptr allExpr = SQLAllExpr_ptr(new SQLAllExpr());

  accept(Token::LPAREN);
  SQLSelect_ptr allSubQuery = createSelectParser()->select();
  allExpr->setSubQuery(allSubQuery);
  accept(Token::RPAREN);

  allSubQuery->setParent(allExpr);

  sqlExpr = allExpr;
  return sqlExpr;
}

BOOL_ptr SQLExprParser::isEnabled(SQLParserFeature_ptr feature) { return lexer->isEnabled(feature); }

SQLExpr_ptr SQLExprParser::methodRest(SQLExpr_ptr expr, string_ptr name, bool aggregate)
{
  lexer->nextToken();

  if (lexer->token()->name->c_str() == Token::DISTINCT.name->c_str())
  {
    lexer->nextToken();

    auto tmp = SQLAggregateOption::DISTINCT;
    SQLAggregateExpr_ptr aggregateExpr = SQLAggregateExpr_ptr(new SQLAggregateExpr(name, tmp));
    // aggregateExpr->setOwner(expr);

    if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
    {
      lexer->nextToken();
    }
    else
    {
      if (lexer->token()->name->c_str() == Token::PLUS.name->c_str())
      {
        string_ptr tmp = make_string_ptr("+");
        aggregateExpr->getArguments()->push_back(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp)));
        lexer->nextToken();
      }
      else
      {
        exprList(aggregateExpr->getArguments(), aggregateExpr);
      }
      accept(Token::RPAREN);
    }
    expr = aggregateExpr;
  }
  else if (aggregate)
  {
    SQLAggregateExpr_ptr methodInvokeExpr = SQLAggregateExpr_ptr(new SQLAggregateExpr(name));
    string_ptr tmp = expr->toString();
    tmp->append("." + *name);
    methodInvokeExpr->setMethodName(tmp);
    if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
    {
      lexer->nextToken();
    }
    else
    {
      if (lexer->token()->name->c_str() == Token::PLUS.name->c_str())
      {
        string_ptr tmp = make_string_ptr("+");
        // methodInvokeExpr->addArgument(new SQLIdentifierExpr(tmp));
        lexer->nextToken();
      }
      else
      {
        exprList(methodInvokeExpr->getArguments(), methodInvokeExpr);
      }
      accept(Token::RPAREN);
    }

    if (lexer->token()->name->c_str() == Token::OVER.name->c_str())
    {
      over(methodInvokeExpr);
    }

    expr = methodInvokeExpr;
  }
  else
  {
    SQLMethodInvokeExpr_ptr methodInvokeExpr = SQLMethodInvokeExpr_ptr(new SQLMethodInvokeExpr(name));
    methodInvokeExpr->setOwner(expr);
    if (lexer->token()->name->c_str() == Token::RPAREN.name->c_str())
    {
      lexer->nextToken();
    }
    else
    {
      if (lexer->token()->name->c_str() == Token::PLUS.name->c_str())
      {
        string_ptr tmp = make_string_ptr("+");
        methodInvokeExpr->addArgument(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(tmp)));
        lexer->nextToken();
      }
      else
      {
        exprList(methodInvokeExpr->getArguments(), methodInvokeExpr);
      }
      accept(Token::RPAREN);
    }

    if (lexer->token()->name->c_str() == Token::OVER.name->c_str())
    {
      SQLAggregateExpr_ptr aggregateExpr = SQLAggregateExpr_ptr(new SQLAggregateExpr(methodInvokeExpr->getMethodName()));
      // aggregateExpr->setOwner(methodInvokeExpr->getOwner());
      // aggregateExpr->getArguments().addAll(methodInvokeExpr->getArguments());
      aggregateExpr->getArguments()->splice(aggregateExpr->getArguments()->end(), *methodInvokeExpr->getArguments());
      over(aggregateExpr);
      methodInvokeExpr = std::dynamic_pointer_cast<SQLMethodInvokeExpr>(aggregateExpr);
    }

    expr = methodInvokeExpr;
  }
  return expr;
}

BOOL_ptr SQLExprParser::isCharType(long hash)
{
  if (hash == FnvHash::Constants::CHAR ||
      hash == FnvHash::Constants::VARCHAR ||
      hash == FnvHash::Constants::NCHAR ||
      hash == FnvHash::Constants::NVARCHAR ||
      hash == FnvHash::Constants::TINYTEXT ||
      hash == FnvHash::Constants::TEXT ||
      hash == FnvHash::Constants::MEDIUMTEXT ||
      hash == FnvHash::Constants::LONGTEXT ||
      hash == FnvHash::Constants::ENUM)
  {
    return BOOL::TRUE;
  }
  else
  {
    return BOOL::FALSE;
  }
}

void SQLExprParser::over(SQLAggregateExpr_ptr aggregateExpr)
{
  lexer->nextToken();

  if (lexer->token()->name->c_str() != Token::LPAREN.name->c_str())
  {
    SQLName_ptr overRef = this->name();
    // aggregateExpr->setOverRef(overRef);
    return;
  }

  SQLOver_ptr over_ = SQLOver_ptr(new SQLOver());
  over(over_);
  aggregateExpr->setOver(over_);
}

void SQLExprParser::over(SQLOver_ptr over_)
{
  lexer->nextToken();

  if (lexer->token()->name->c_str() == Token::PARTITION.name->c_str() ||
      lexer->identifierEquals(L"PARTITION"))
  {
    lexer->nextToken();
    accept(Token::BY);

    if (lexer->token()->name->c_str() == (Token::LPAREN.name->c_str()))
    {
      lexer->nextToken();
      exprList(over_->getPartitionBy(), over_);
      accept(Token::RPAREN);

      if (over_->getPartitionBy()->size() == 1)
      {
        if (lexer->token()->name->c_str() == Token::SLASH.name->c_str() ||
            lexer->token()->name->c_str() == Token::DIV.name->c_str() ||
            lexer->token()->name->c_str() == Token::STAR.name->c_str() ||
            lexer->token()->name->c_str() == Token::PLUS.name->c_str() ||
            lexer->token()->name->c_str() == Token::SUB.name->c_str())
        {
          auto it = over_->getPartitionBy()->begin();
          std::advance(it, 0);
          SQLExpr_ptr first = this->exprRest((*it));
          // first.setParent(over_);
          over_->getPartitionBy()->insert(it, first);
        }

        if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
        {
          lexer->nextToken();
          exprList(over_->getPartitionBy(), over_);
        }
      }
    }
    else if (lexer->token()->name->c_str() == Token::ALL.name->c_str())
    {
      SQLName_ptr name = (this->name());
      // name->setParent(over_);
      over_->getPartitionBy()->push_back(name);
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        exprList(over_->getPartitionBy(), over_);
      }
    }
    else
    {
      exprList(over_->getPartitionBy(), over_);
    }
  }

  over_->setOrderBy(parseOrderBy());
  // over_->setDistributeBy(parseDistributeBy());
  // over_->setSortBy(parseSortBy());
  // over_->setClusterBy(parseClusterBy());

  if (lexer->token()->name->c_str() == Token::OF.name->c_str())
  {
    lexer->nextToken();
    SQLName_ptr of = this->name();
    // over_->setOf(of);
  }

  // SQLOver::WindowingType windowingType = NULL;
  // if (lexer->identifierEquals(FnvHash::Constants::ROWS) || lexer->token()->name->c_str() == Token::ROWS)
  // {
  //   windowingType = SQLOver::WindowingType::ROWS;
  // }
  // else if (lexer->identifierEquals(FnvHash::Constants::RANGE))
  // {
  //   windowingType = SQLOver::WindowingType::RANGE;
  // }

  // if (windowingType != NULL)
  // {
  //   over_->setWindowingType(windowingType);
  //   lexer->nextToken();

  //   if (lexer->token()->name->c_str() == Token::BETWEEN)
  //   {
  //     lexer->nextToken();

  //     if  (lexer->token()->name->c_str() == Token::LITERAL_INT || lexer->token()->name->c_str() == Token::LITERAL_FLOAT || lexer->token()->name->c_str() == Token::LITERAL_CHARS || lexer->token()->name->c_str() == Token::CAST)
  //     {
  //       SQLExpr_ptr  betweenBegin = this->additive();
  //       over_->setWindowingBetweenBegin(betweenBegin);
  //     }
  //     else if (lexer->token()->name->c_str() == Token::IDENTIFIER)
  //     {
  //       long hash = lexer->hashLCase();

  //       if (hash != FnvHash::Constants::PRECEDING && hash != FnvHash::Constants::FOLLOWING && hash != FnvHash::Constants::CURRENT && hash != FnvHash::Constants::UNBOUNDED)
  //       {
  //         SQLExpr_ptr  betweenBegin = this->primary();
  //         over_->setWindowingBetweenBegin(betweenBegin);
  //       }
  //     }
  //     else if  (lexer->token()->name->c_str() == Token::INTERVAL)
  //     {
  //       SQLExpr_ptr  betweenBegin = this->primary();
  //       over_->setWindowingBetweenBegin(betweenBegin);
  //     }

  //     SQLOver::WindowingBound beginBound = parseWindowingBound();
  //     if (beginBound != NULL)
  //     {
  //       over_->setWindowingBetweenBeginBound(beginBound);
  //     }

  //     accept(Token::AND);

  //     if  (lexer->token()->name->c_str() == Token::LITERAL_INT || lexer->token() == Token::LITERAL_FLOAT || lexer->token() == Token::LITERAL_CHARS)
  //     {
  //       SQLExpr_ptr  betweenEnd = this->additive();
  //       over_->setWindowingBetweenEnd(betweenEnd);
  //     }
  //     else if  (lexer->token()->name->c_str() == Token::INTERVAL)
  //     {
  //       SQLExpr_ptr  betweenBegin = this->additive();
  //       over_->setWindowingBetweenEnd(betweenBegin);
  //     }
  //     else if  (lexer->token()->name->c_str() == Token::IDENTIFIER)
  //     {
  //       long hash = lexer->hashLCase();

  //       if (hash != FnvHash::Constants::PRECEDING && hash != FnvHash::Constants::FOLLOWING && hash != FnvHash::Constants::CURRENT && hash != FnvHash::Constants::UNBOUNDED)
  //       {
  //         SQLExpr betweenBegin = this->additive();
  //         over_->setWindowingBetweenEnd(betweenBegin);
  //       }
  //     }

  //     SQLOver::WindowingBound endBound = parseWindowingBound();
  //     if (endBound != NULL)
  //     {
  //       over_->setWindowingBetweenEndBound(endBound);
  //     }
  //   }
  //   else
  //   {
  //     if  (lexer->token()->name->c_str() == Token::LITERAL_INT || lexer->token() == Token::LITERAL_FLOAT || lexer->token() == Token::LITERAL_CHARS || lexer->token() == Token::INTERVAL)
  //     {
  //       SQLExpr_ptr  betweenBegin = this->additive();
  //       over_->setWindowingBetweenBegin(betweenBegin);
  //     }
  //     else if  (lexer->token()->name->c_str() == Token::IDENTIFIER)
  //     {
  //       long hash = lexer->hashLCase();

  //       if (hash != FnvHash::Constants::PRECEDING && hash != FnvHash::Constants::FOLLOWING && hash != FnvHash::Constants::CURRENT && hash != FnvHash::Constants::UNBOUNDED)
  //       {
  //         SQLExpr betweenBegin = this->additive();
  //         over_->setWindowingBetweenBegin(betweenBegin);
  //       }
  //     }

  //     SQLOver::WindowingBound beginBound = parseWindowingBound();
  //     if (beginBound != NULL)
  //     {
  //       over_->setWindowingBetweenBeginBound(beginBound);
  //     }
  //   }
  // }

  if (lexer->identifierEquals(FnvHash::Constants::EXCLUDE))
  {
    lexer->nextToken();
    acceptIdentifier("CURRENT");
    acceptIdentifier("ROW");
    // over_->setExcludeCurrentRow(BOOL::TRUE);
  }

  accept(Token::RPAREN);
}

SQLName_ptr SQLExprParser::name()
{
  string_ptr identName;
  long hash = 0;
  if (lexer->token()->name->c_str() == Token::LITERAL_ALIAS.name->c_str())
  {
    identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
  {
    identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));

    char c0 = identName->at(0);
    if (c0 != '[')
    {
      hash = lexer->hashLCase();
    }
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::LITERAL_CHARS.name->c_str())
  {
    identName = make_string_ptr('\'' + encode_util::UnicodeToUTF8(*lexer->stringVal()) + '\'');
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::VARIANT.name->c_str())
  {
    identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
    lexer->nextToken();
  }
  else
  {
    if (lexer->token()->name->c_str() == Token::MODE.name->c_str() ||
        lexer->token()->name->c_str() == Token::ERRORS.name->c_str() ||
        lexer->token()->name->c_str() == Token::NOWAIT.name->c_str() ||
        lexer->token()->name->c_str() == Token::COMMIT.name->c_str() ||
        lexer->token()->name->c_str() == Token::PCTFREE.name->c_str() ||
        lexer->token()->name->c_str() == Token::INITRANS.name->c_str() ||
        lexer->token()->name->c_str() == Token::MAXTRANS.name->c_str() ||
        lexer->token()->name->c_str() == Token::SEGMENT.name->c_str() ||
        lexer->token()->name->c_str() == Token::CREATION.name->c_str() ||
        lexer->token()->name->c_str() == Token::IMMEDIATE.name->c_str() ||
        lexer->token()->name->c_str() == Token::DEFERRED.name->c_str() ||
        lexer->token()->name->c_str() == Token::STORAGE.name->c_str() ||
        lexer->token()->name->c_str() == Token::NEXT.name->c_str() ||
        lexer->token()->name->c_str() == Token::MINEXTENTS.name->c_str() ||
        lexer->token()->name->c_str() == Token::MAXEXTENTS.name->c_str() ||
        lexer->token()->name->c_str() == Token::MAXSIZE.name->c_str() ||
        lexer->token()->name->c_str() == Token::PCTINCREASE.name->c_str() ||
        lexer->token()->name->c_str() == Token::FLASH_CACHE.name->c_str() ||
        lexer->token()->name->c_str() == Token::CELL_FLASH_CACHE.name->c_str() ||
        lexer->token()->name->c_str() == Token::NONE.name->c_str() ||
        lexer->token()->name->c_str() == Token::LOB.name->c_str() ||
        lexer->token()->name->c_str() == Token::STORE.name->c_str() ||
        lexer->token()->name->c_str() == Token::ROW.name->c_str() ||
        lexer->token()->name->c_str() == Token::CHUNK.name->c_str() ||
        lexer->token()->name->c_str() == Token::CACHE.name->c_str() ||
        lexer->token()->name->c_str() == Token::NOCACHE.name->c_str() ||
        lexer->token()->name->c_str() == Token::LOGGING.name->c_str() ||
        lexer->token()->name->c_str() == Token::NOCOMPRESS.name->c_str() ||
        lexer->token()->name->c_str() == Token::KEEP_DUPLICATES.name->c_str() ||
        lexer->token()->name->c_str() == Token::EXCEPTIONS.name->c_str() ||
        lexer->token()->name->c_str() == Token::PURGE.name->c_str() ||
        lexer->token()->name->c_str() == Token::INITIALLY.name->c_str() ||
        lexer->token()->name->c_str() == Token::END.name->c_str() ||
        lexer->token()->name->c_str() == Token::COMMENT.name->c_str() ||
        lexer->token()->name->c_str() == Token::ENABLE.name->c_str() ||
        lexer->token()->name->c_str() == Token::DISABLE.name->c_str() ||
        lexer->token()->name->c_str() == Token::SEQUENCE.name->c_str() ||
        lexer->token()->name->c_str() == Token::USER.name->c_str() ||
        lexer->token()->name->c_str() == Token::ANALYZE.name->c_str() ||
        lexer->token()->name->c_str() == Token::OPTIMIZE.name->c_str() ||
        lexer->token()->name->c_str() == Token::GRANT.name->c_str() ||
        lexer->token()->name->c_str() == Token::REVOKE.name->c_str() ||
        lexer->token()->name->c_str() == Token::BINARY.name->c_str() ||
        lexer->token()->name->c_str() == Token::OVER.name->c_str() ||
        lexer->token()->name->c_str() == Token::ORDER.name->c_str() ||
        lexer->token()->name->c_str() == Token::DO.name->c_str() ||
        lexer->token()->name->c_str() == Token::INNER.name->c_str() ||
        lexer->token()->name->c_str() == Token::JOIN.name->c_str() ||
        lexer->token()->name->c_str() == Token::TYPE.name->c_str() ||
        lexer->token()->name->c_str() == Token::FUNCTION.name->c_str() ||
        lexer->token()->name->c_str() == Token::KEY.name->c_str() ||
        lexer->token()->name->c_str() == Token::UNIQUE.name->c_str() ||
        lexer->token()->name->c_str() == Token::SCHEMA.name->c_str() ||
        lexer->token()->name->c_str() == Token::INTERVAL.name->c_str() ||
        lexer->token()->name->c_str() == Token::EXPLAIN.name->c_str() ||
        lexer->token()->name->c_str() == Token::SET.name->c_str() ||
        lexer->token()->name->c_str() == Token::TABLESPACE.name->c_str() ||
        lexer->token()->name->c_str() == Token::PARTITION.name->c_str() ||
        lexer->token()->name->c_str() == Token::CLOSE.name->c_str() ||
        lexer->token()->name->c_str() == Token::INOUT.name->c_str() ||
        lexer->token()->name->c_str() == Token::GOTO.name->c_str() ||
        lexer->token()->name->c_str() == Token::DEFAULT.name->c_str() ||
        lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str() ||
        lexer->token()->name->c_str() == Token::WITH.name->c_str() ||
        lexer->token()->name->c_str() == Token::ANY.name->c_str() ||
        lexer->token()->name->c_str() == Token::BEGIN.name->c_str() ||
        lexer->token()->name->c_str() == Token::CAST.name->c_str() ||
        lexer->token()->name->c_str() == Token::COMPUTE.name->c_str() ||
        lexer->token()->name->c_str() == Token::ESCAPE.name->c_str() ||
        lexer->token()->name->c_str() == Token::EXCEPT.name->c_str() ||
        lexer->token()->name->c_str() == Token::FULL.name->c_str() ||
        lexer->token()->name->c_str() == Token::INTERSECT.name->c_str() ||
        lexer->token()->name->c_str() == Token::MERGE.name->c_str() ||
        lexer->token()->name->c_str() == Token::MINUS.name->c_str() ||
        lexer->token()->name->c_str() == Token::OPEN.name->c_str() ||
        lexer->token()->name->c_str() == Token::SOME.name->c_str() ||
        lexer->token()->name->c_str() == Token::TRUNCATE.name->c_str() ||
        lexer->token()->name->c_str() == Token::UNTIL.name->c_str() ||
        lexer->token()->name->c_str() == Token::VIEW.name->c_str() ||
        lexer->token()->name->c_str() == Token::GROUP.name->c_str() ||
        lexer->token()->name->c_str() == Token::INDEX.name->c_str() ||
        lexer->token()->name->c_str() == Token::DESC.name->c_str() ||
        lexer->token()->name->c_str() == Token::ALL.name->c_str() ||
        lexer->token()->name->c_str() == Token::SHOW.name->c_str() ||
        lexer->token()->name->c_str() == Token::FOR.name->c_str() ||
        lexer->token()->name->c_str() == Token::LEAVE.name->c_str() ||
        lexer->token()->name->c_str() == Token::REPEAT.name->c_str() ||
        lexer->token()->name->c_str() == Token::LOOP.name->c_str() ||
        lexer->token()->name->c_str() == Token::IS.name->c_str() ||
        lexer->token()->name->c_str() == Token::LOCK.name->c_str() ||
        lexer->token()->name->c_str() == Token::REFERENCES.name->c_str())
    {
      identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
      lexer->nextToken();
    }
    else if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str() ||
             lexer->token()->name->c_str() == Token::CHECK.name->c_str() ||
             lexer->token()->name->c_str() == Token::VALUES.name->c_str() ||
             lexer->token()->name->c_str() == Token::IN.name->c_str() ||
             lexer->token()->name->c_str() == Token::OUT.name->c_str() ||
             lexer->token()->name->c_str() == Token::LIMIT.name->c_str() ||
             lexer->token()->name->c_str() == Token::TRIGGER.name->c_str() ||
             lexer->token()->name->c_str() == Token::USE.name->c_str() ||
             lexer->token()->name->c_str() == Token::LIKE.name->c_str() ||
             lexer->token()->name->c_str() == Token::DISTRIBUTE.name->c_str() ||
             lexer->token()->name->c_str() == Token::DELETE.name->c_str() ||
             lexer->token()->name->c_str() == Token::UPDATE.name->c_str() ||
             lexer->token()->name->c_str() == Token::PROCEDURE.name->c_str() ||
             lexer->token()->name->c_str() == Token::LEFT.name->c_str() ||
             lexer->token()->name->c_str() == Token::RIGHT.name->c_str() ||
             lexer->token()->name->c_str() == Token::TABLE.name->c_str() ||
             lexer->token()->name->c_str() == Token::RLIKE.name->c_str() ||
             lexer->token()->name->c_str() == Token::CREATE.name->c_str() ||
             lexer->token()->name->c_str() == Token::PARTITIONED.name->c_str() ||
             lexer->token()->name->c_str() == Token::UNION.name->c_str() ||
             lexer->token()->name->c_str() == Token::PRIMARY.name->c_str() ||
             lexer->token()->name->c_str() == Token::TO.name->c_str() ||
             lexer->token()->name->c_str() == Token::DECLARE.name->c_str() ||
             lexer->token()->name->c_str() == Token::AS.name->c_str() ||
             lexer->token()->name->c_str() == Token::BY.name->c_str() ||
             lexer->token()->name->c_str() == Token::EXISTS.name->c_str() ||
             lexer->token()->name->c_str() == Token::FOREIGN.name->c_str() ||
             lexer->token()->name->c_str() == Token::ALTER.name->c_str() ||
             lexer->token()->name->c_str() == Token::ASC.name->c_str() ||
             lexer->token()->name->c_str() == Token::XNULL.name->c_str() ||
             lexer->token()->name->c_str() == Token::CURSOR.name->c_str() ||
             lexer->token()->name->c_str() == Token::FETCH.name->c_str() ||
             lexer->token()->name->c_str() == Token::DATABASE.name->c_str())
    {
      if (dbType->name->c_str() == DbType::odps.name->c_str())
      {
        identName = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
        lexer->nextToken();
      }
      else
      {
        throw new ParserException(make_string_ptr("illegal name, " + encode_util::UnicodeToUTF8(lexer->info())));
      }
    }
    else
    {
      throw new ParserException(make_string_ptr("illegal name, " + encode_util::UnicodeToUTF8(lexer->info())));
    }
  }

  if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(SQLParserFeature::IgnoreNameQuotes.mask, SQLParserFeature::IgnoreNameQuotes.name))))
  {
    identName = SQLUtils::forcedNormalize(identName, dbType);
  }

  LOG_INFO << "identName:" << identName;
  SQLIdentifierExpr_ptr identifierExpr(new SQLIdentifierExpr(identName, hash));
  if (lexer->keepSourceLocation)
  {
    lexer->computeRowAndColumn();
    identifierExpr->setSourceLine(lexer->posLine);
    identifierExpr->setSourceColumn(lexer->posColumn);
  }

  SQLName_ptr name = std::dynamic_pointer_cast<SQLIdentifierExpr>(identifierExpr);

  name = (nameRest(name));

  return name;
}

SQLLimit_ptr SQLExprParser::parseLimit()
{
  if (lexer->token()->name->c_str() != Token::LIMIT.name->c_str())
  {
    return NULL;
  }

  SQLLimit_ptr limit = SQLLimit_ptr(new SQLLimit());
  lexer->nextTokenValue();

  SQLExpr_ptr temp;
  if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str())
  {
    temp = SQLIntegerExpr_ptr(new SQLIntegerExpr(lexer->integerValue()));
    lexer->nextTokenComma();
    if (lexer->token()->name->c_str() != Token::COMMA.name->c_str() &&
        lexer->token()->name->c_str() != Token::XEOF.name->c_str() &&
        lexer->token()->name->c_str() != Token::IDENTIFIER.name->c_str())
    {
      temp = this->primaryRest(temp);
      temp = this->exprRest(temp);
    }
  }
  else
  {
    temp = this->getExpr();
  }

  if (lexer->token()->name->c_str() == (Token::COMMA.name->c_str()))
  {
    limit->setOffset(temp);
    lexer->nextTokenValue();

    SQLExpr_ptr rowCount;
    if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str())
    {
      rowCount = SQLIntegerExpr_ptr(new SQLIntegerExpr(lexer->integerValue()));
      lexer->nextToken();
      if (lexer->token()->name->c_str() != Token::XEOF.name->c_str() &&
          lexer->token()->name->c_str() != Token::IDENTIFIER.name->c_str())
      {
        rowCount = this->primaryRest(rowCount);
        rowCount = this->exprRest(rowCount);
      }
    }
    else
    {
      rowCount = this->getExpr();
    }

    limit->setRowCount(rowCount);
  }
  else if (lexer->identifierEquals(FnvHash::Constants::OFFSET))
  {
    limit->setRowCount(temp);
    lexer->nextToken();
    limit->setOffset(this->getExpr());
  }
  else
  {
    limit->setRowCount(temp);
  }

  if (lexer->token()->name->c_str() == Token::BY.name->c_str() &&
      dbType->name->c_str() == DbType::clickhouse.name->c_str())
  {
    lexer->nextToken();

    for (;;)
    {
      SQLExpr_ptr item = this->getExpr();
      limit->addBy(item);
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
        continue;
      }
      break;
    }
  }

  return limit;
}

void SQLExprParser::setAllowIdentifierMethod(BOOL_ptr allowIdentifierMethod)
{
  this->allowIdentifierMethod = allowIdentifierMethod;
}

SQLCharExpr_ptr SQLExprParser::charExpr()
{
  string_ptr tmp = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
  SQLCharExpr_ptr charExpr = SQLCharExpr_ptr(new SQLCharExpr(tmp));
  accept(Token::LITERAL_CHARS);
  return charExpr;
}

int SQLExprParser::parseIntValue()
{
  if (lexer->token()->name->c_str() == Token::LITERAL_INT.name->c_str())
  {
    long number = this->lexer->integerValue();
    int intVal = number;
    lexer->nextToken();
    return intVal;
  }
  else
  {
    throw new ParserException(make_string_ptr("not int. " + encode_util::UnicodeToUTF8(lexer->info())));
  }
}

void SQLExprParser::names(SQLName_list_ptr exprCol)
{
  SQLObject_ptr sqlobj = SQLObject_ptr(new SQLObject());
  names(exprCol, sqlobj);
}

void SQLExprParser::names(SQLName_list_ptr exprCol, SQLObject_ptr parent)
{
  if (lexer->token()->name->c_str() == Token::RBRACE.name->c_str())
  {
    return;
  }

  if (lexer->token()->name->c_str() == Token::XEOF.name->c_str())
  {
    return;
  }

  SQLName_ptr name_ = name();
  name_->setParent(parent);
  exprCol->push_back(name_);

  while (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
  {
    lexer->nextToken();

    // if (instanceof<SQLObject, SQLLateralViewTableSource>(parent )  && lexer->token()->name->c_str() == Token::XNULL) {
    //   string_ptr  tmp = lexer->stringVal();
    //     name_ = new SQLIdentifierExpr(tmp);
    //     lexer->nextToken();
    // } else {
    //     name_ = name();
    // }

    name_->setParent(parent);
    exprCol->push_back(name_);
  }
}

void SQLExprParser::orderBy(SQLSelectOrderByItem_list_ptr items, SQLObject_ptr parent)
{
  SQLSelectOrderByItem_ptr item = parseSelectOrderByItem();
  item->setParent(parent);
  items->push_back(item);
  while (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
  {
    lexer->nextToken();
    item = parseSelectOrderByItem();
    item->setParent(parent);
    items->push_back(item);
  }
}

SQLCommentHint_ptr SQLExprParser::parseHint()
{
  string_ptr text = make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()));
  LOG_INFO << "text:" << text;
  SQLCommentHint_ptr hint;

  if (lexer->isEnabled(SQLParserFeature_ptr(new SQLParserFeature(SQLParserFeature::TDDLHint.mask, SQLParserFeature::TDDLHint.name))) &&
      (StringUtils::startWith(text, make_string_ptr("+ TDDL")) ||
       StringUtils::startWith(text, make_string_ptr("+TDDL")) ||
       StringUtils::startWith(text, make_string_ptr("!TDDL")) ||
       StringUtils::startWith(text, make_string_ptr("TDDL"))))
  {
    LOG_INFO << "TDDLHint";
    hint = TDDLHint_ptr(new TDDLHint(text));
  }
  else
  {
    LOG_INFO << "TDDLHint";
    hint = SQLCommentHint_ptr(new SQLCommentHint(text));
  }

  if (lexer->commentCount > 0)
  {
    hint->addBeforeComment(lexer->comments);
  }

  lexer->nextToken();
  return hint;
}

void SQLExprParser::parseIndex(SQLIndexDefinition_ptr indexDefinition)
{
  if (lexer->token()->name->c_str() == Token::CONSTRAINT.name->c_str())
  {
    indexDefinition->setHasConstraint(BOOL::TRUE);
    lexer->nextToken();
    if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str() &&
        !lexer->identifierEquals(FnvHash::Constants::GLOBAL) &&
        !lexer->identifierEquals(FnvHash::Constants::LOCAL) &&
        !lexer->identifierEquals(FnvHash::Constants::SPATIAL))
    {
      indexDefinition->setSymbol(name());
    }
  }

  if (lexer->identifierEquals(FnvHash::Constants::GLOBAL))
  {
    indexDefinition->setGlobal(BOOL::TRUE);
    lexer->nextToken();
  }
  else if (lexer->identifierEquals(FnvHash::Constants::LOCAL))
  {
    indexDefinition->setLocal(BOOL::TRUE);
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == Token::FULLTEXT.name->c_str() ||
      lexer->token()->name->c_str() == Token::UNIQUE.name->c_str() ||
      lexer->token()->name->c_str() == Token::PRIMARY.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::SPATIAL) ||
      lexer->identifierEquals(FnvHash::Constants::CLUSTERED) ||
      lexer->identifierEquals(FnvHash::Constants::CLUSTERING) ||
      lexer->identifierEquals(FnvHash::Constants::ANN))
  {
    indexDefinition->setType(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
    lexer->nextToken();
  }

  if (lexer->identifierEquals(FnvHash::Constants::GLOBAL))
  {
    indexDefinition->setGlobal(BOOL::TRUE);
    lexer->nextToken();
  }
  else if (lexer->identifierEquals(FnvHash::Constants::LOCAL))
  {
    indexDefinition->setLocal(BOOL::TRUE);
    lexer->nextToken();
  }

  if (lexer->token()->name->c_str() == Token::INDEX.name->c_str())
  {
    indexDefinition->setIndex(BOOL::TRUE);
    lexer->nextToken();
  }
  else if (lexer->token()->name->c_str() == Token::KEY.name->c_str())
  {
    indexDefinition->setKey(BOOL::TRUE);
    lexer->nextToken();
  }

  while (lexer->token()->name->c_str() != Token::LPAREN.name->c_str() &&
         lexer->token()->name->c_str() != Token::ON.name->c_str())
  {
    if (DbType::mysql.name->c_str() == dbType->name->c_str() &&
        lexer->identifierEquals(FnvHash::Constants::USING))
    {
      lexer->nextToken();
      indexDefinition->getOptions()->setIndexType(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
      lexer->nextToken();
    }
    else if ((DbType::mysql.name->c_str() == dbType->name->c_str() ||
              DbType::ads.name->c_str() == dbType->name->c_str()) &&
             lexer->identifierEquals(L"HASHMAP"))
    {
      lexer->nextToken();
      indexDefinition->setHashMapType(BOOL::TRUE);
      // indexDefinition->getParent()->putAttribute("ads.index", Boolean.TRUE);
    }
    else if ((DbType::mysql.name->c_str() == dbType->name->c_str() ||
              DbType::ads.name->c_str() == dbType->name->c_str()) &&
             lexer->identifierEquals(FnvHash::Constants::HASH))
    {
      lexer->nextToken();
      indexDefinition->setHashType(BOOL::TRUE);
      // indexDefinition->getParent()->putAttribute("ads.index", Boolean.TRUE);
    }
    else
    {
      indexDefinition->setName(name());
    }
  }

  if (lexer->token()->name->c_str() == Token::ON.name->c_str())
  {
    lexer->nextToken();
    indexDefinition->setTable(SQLExprTableSource_ptr(new SQLExprTableSource(name())));
  }

  parseIndexRest(indexDefinition, indexDefinition->getParent());

// Options, partitions.
_opts:
  while (BOOL::TRUE)
  {
    if (lexer->token()->name->c_str() == Token::COMMENT.name->c_str())
    {
      lexer->nextToken();
      indexDefinition->getOptions()->setComment(primary());
    }
    else if ((DbType::mysql.name->c_str() == dbType->name->c_str()) &&
             lexer->identifierEquals(L"INVISIBLE"))
    {
      lexer->nextToken();
      indexDefinition->getOptions()->setInvisible(BOOL::TRUE);
    }
    else if ((DbType::mysql.name->c_str() == dbType->name->c_str()) &&
             lexer->identifierEquals(L"VISIBLE"))
    {
      lexer->nextToken();
      indexDefinition->getOptions()->setVisible(BOOL::TRUE);
    }
    else if ((DbType::mysql.name->c_str() == dbType->name->c_str()) &&
             lexer->identifierEquals(L"GLOBAL"))
    {
      lexer->nextToken();
      indexDefinition->getOptions()->setGlobal(BOOL::TRUE);
    }
    else if ((DbType::mysql.name->c_str() == dbType->name->c_str()) &&
             lexer->identifierEquals(L"LOCAL"))
    {
      lexer->nextToken();
      indexDefinition->getOptions()->setLocal(BOOL::TRUE);
    }
    else if ((DbType::mysql.name->c_str() == dbType->name->c_str()) &&
             lexer->token()->name->c_str() == Token::HINT.name->c_str() &&
             StringUtils::iequals(encode_util::UnicodeToUTF8(*lexer->stringVal()), "!80000 INVISIBLE"))
    {
      lexer->nextToken();
      indexDefinition->getOptions()->setInvisible(BOOL::TRUE);
    }
    else if (DbType::mysql.name->c_str() == dbType->name->c_str())
    {
      if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
      {
        Lexer_SavePoint_ptr mark = lexer->mark();
        lexer->nextToken();
        if (lexer->identifierEquals(L"PARSER"))
        {
          lexer->nextToken();
          indexDefinition->getOptions()->setParserName(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
          lexer->nextToken();
          break;
        }
        lexer->reset(mark);
        for (;;)
        {
          if (lexer->token()->name->c_str() == Token::WITH.name->c_str())
          {
            lexer->nextToken();
            // Part from original MySqlCreateTableParser.
            if (lexer->token()->name->c_str() == Token::INDEX.name->c_str())
            {
              lexer->nextToken();
              acceptIdentifier("ANALYZER");
              indexDefinition->setIndexAnalyzerName(name());
              continue;
            }
            else if (lexer->identifierEquals(FnvHash::Constants::QUERY))
            {
              lexer->nextToken();
              acceptIdentifier("ANALYZER");
              indexDefinition->setQueryAnalyzerName(name());
              continue;
            }
            else if (lexer->identifierEquals(FnvHash::Constants::ANALYZER))
            {
              lexer->nextToken();
              SQLName_ptr name_ = name();
              indexDefinition->setAnalyzerName(name_);
              break;
            }
            else if (lexer->identifierEquals(L"DICT"))
            {
              lexer->nextToken();
              indexDefinition->setWithDicName(name());
              continue;
            }
          }
          break;
        }
      }
      else if (lexer->token()->name->c_str() == Token::LOCK.name->c_str())
      {
        lexer->nextToken();
        if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
        {
          lexer->nextToken();
        }
        indexDefinition->getOptions()->setLock(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
        lexer->nextToken();
      }
      else if (lexer->token()->name->c_str() == Token::IDENTIFIER.name->c_str())
      {
        if (lexer->identifierEquals(FnvHash::Constants::KEY_BLOCK_SIZE) ||
            lexer->identifierEquals(FnvHash::Constants::BLOCK_SIZE))
        {
          lexer->nextToken();
          if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
          {
            lexer->nextToken();
          }
          indexDefinition->getOptions()->setKeyBlockSize(expr());
        }
        else if (lexer->identifierEquals(FnvHash::Constants::USING))
        {
          lexer->nextToken();
          indexDefinition->getOptions()->setIndexType(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
          lexer->nextToken();
        }
        else if (lexer->identifierEquals(FnvHash::Constants::ALGORITHM))
        {
          lexer->nextToken();
          if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
          {
            lexer->nextToken();
          }
          indexDefinition->getOptions()->setAlgorithm(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal())));
          lexer->nextToken();
        }
        else if (lexer->identifierEquals(FnvHash::Constants::DISTANCEMEASURE))
        {
          // Caution: Not in MySql documents.
          SQLExpr_ptr key = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()))));
          lexer->nextToken();
          if (lexer->token()->name->c_str() == Token::EQ.name->c_str())
          {
            lexer->nextToken();
          }
          SQLAssignItem_ptr item = SQLAssignItem_ptr(new SQLAssignItem(key, primary()));
          if (indexDefinition->getParent() != nullptr)
          {
            item->setParent(indexDefinition->getParent());
          }
          else
          {
            item->setParent(indexDefinition);
          }
          // Add both with same object.
          indexDefinition->getOptions()->getOtherOptions()->push_back(item);
          indexDefinition->getCompatibleOptions()->push_back(item);
        }
        else if (lexer->identifierEquals(FnvHash::Constants::DBPARTITION))
        {
          lexer->nextToken();
          accept(Token::BY);
          indexDefinition->setDbPartitionBy(primary());
        }
        else if (lexer->identifierEquals(FnvHash::Constants::TBPARTITION))
        {
          lexer->nextToken();
          accept(Token::BY);
          SQLExpr_ptr expr_ = expr();
          if (lexer->identifierEquals(FnvHash::Constants::STARTWITH))
          {
            lexer->nextToken();
            SQLExpr_ptr start = primary();
            acceptIdentifier("ENDWITH");
            SQLExpr_ptr end = primary();
            expr_ = SQLBetweenExpr_ptr(new SQLBetweenExpr(expr_, start, end));
          }
          indexDefinition->setTbPartitionBy(expr_);
        }
        else if (lexer->identifierEquals(FnvHash::Constants::TBPARTITIONS))
        {
          lexer->nextToken();
          indexDefinition->setTbPartitions(primary());
          //} else if (lexer->identifierEquals(FnvHash::Constants::GLOBAL)) {
          //    lexer->nextToken();
          //    indexDefinition->setGlobal(BOOL::TRUE);
        }
        else
        {
          goto _opts;
        }
      }
      else
      {
        goto _opts;
      }
    }
    else
    {
      goto _opts;
    }
  }
}

void SQLExprParser::parseIndexRest(SQLIndex_ptr idx)
{
  parseIndexRest(idx, std::dynamic_pointer_cast<SQLObject>(idx));
}

void SQLExprParser::parseIndexRest(SQLIndex_ptr idx, SQLObject_ptr parent)
{
  accept(Token::LPAREN);
  for (;;)
  {
    SQLSelectOrderByItem_ptr selectOrderByItem = this->parseSelectOrderByItem();
    selectOrderByItem->setParent(parent);
    idx->getColumns()->push_back(selectOrderByItem);
    if (!(lexer->token()->name->c_str() == (Token::COMMA.name->c_str())))
    {
      break;
    }
    else
    {
      lexer->nextToken();
    }
  }
  accept(Token::RPAREN);

  if (lexer->identifierEquals(FnvHash::Constants::COVERING))
  {
    Lexer_SavePoint_ptr mark = lexer->mark();

    lexer->nextToken();

    if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
    {
      lexer->nextToken();
    }
    else
    {
      lexer->reset(mark);
      return;
    }

    for (;;)
    {
      SQLName_ptr name = this->name();
      name->setParent(parent);
      idx->getCovering()->push_back(name);
      if (lexer->token()->name->c_str() == Token::COMMA.name->c_str())
      {
        lexer->nextToken();
      }
      else
      {
        break;
      }
    }

    accept(Token::RPAREN);
  }
}

SQLIntegerExpr_ptr SQLExprParser::integerExpr()
{
  SQLIntegerExpr_ptr intExpr = nullptr;
  if (lexer->token()->name->c_str() == Token::SUB.name->c_str())
  {
    lexer->nextToken();
    intExpr = SQLIntegerExpr_ptr(new SQLIntegerExpr(lexer->integerValue() * -1));
  }
  else
  {
    intExpr = SQLIntegerExpr_ptr(new SQLIntegerExpr(lexer->integerValue()));
  }
  accept(Token::LITERAL_INT);
  return intExpr;
}

SQLPartitionValue_ptr SQLExprParser::parsePartitionValues()
{
  if (lexer->token()->name->c_str() != Token::VALUES.name->c_str())
  {
    return nullptr;
  }
  lexer->nextToken();

  SQLPartitionValue_ptr values = nullptr;

  if (lexer->token()->name->c_str() == Token::IN.name->c_str())
  {
    lexer->nextToken();
    values = SQLPartitionValue_ptr(new SQLPartitionValue(SQLPartitionValue_Operator::In));

    accept(Token::LPAREN);
    this->exprList(values->getItems(), std::dynamic_pointer_cast<SQLObject>(values));
    accept(Token::RPAREN);
  }
  else if (lexer->identifierEquals(FnvHash::Constants::LESS))
  {
    lexer->nextToken();
    acceptIdentifier("THAN");

    values = SQLPartitionValue_ptr(new SQLPartitionValue(SQLPartitionValue_Operator::LessThan));

    if (lexer->identifierEquals(FnvHash::Constants::MAXVALUE))
    {
      SQLIdentifierExpr_ptr maxValue = SQLIdentifierExpr_ptr(new SQLIdentifierExpr(make_string_ptr(encode_util::UnicodeToUTF8(*lexer->stringVal()))));
      lexer->nextToken();
      maxValue->setParent(std::dynamic_pointer_cast<SQLObject>(values));
      values->addItem(maxValue);
    }
    else
    {
      accept(Token::LPAREN);
      this->exprList(values->getItems(), std::dynamic_pointer_cast<SQLObject>(values));
      accept(Token::RPAREN);
    }
  }
  else if (lexer->token()->name->c_str() == Token::LPAREN.name->c_str())
  {
    values = SQLPartitionValue_ptr(new SQLPartitionValue(SQLPartitionValue_Operator::List));
    lexer->nextToken();
    this->exprList(values->getItems(), std::dynamic_pointer_cast<SQLObject>(values));
    accept(Token::RPAREN);
  }

  return values;
}

SQLExternalRecordFormat_ptr SQLExprParser::parseRowFormat()
{
  lexer->nextToken();
  acceptIdentifier("FORMAT");

  if (lexer->identifierEquals(FnvHash::Constants::DELIMITED))
  {
    lexer->nextToken();
  }

  SQLExternalRecordFormat_ptr format = SQLExternalRecordFormat_ptr(new SQLExternalRecordFormat());

  if (lexer->identifierEquals(FnvHash::Constants::FIELDS))
  {
    lexer->nextToken();
    acceptIdentifier("TERMINATED");
    accept(Token::BY);

    format->setTerminatedBy(this->expr());
  }
  else if (lexer->identifierEquals(L"FIELD"))
  {
    throw new ParserException(make_string_ptr("syntax error, expect FIELDS, " + encode_util::UnicodeToUTF8(lexer->info())));
  }

  if (lexer->token()->name->c_str() == Token::ESCAPE.name->c_str() ||
      lexer->identifierEquals(FnvHash::Constants::ESCAPED))
  {
    lexer->nextToken();
    accept(Token::BY);
    format->setEscapedBy(this->expr());
  }

  if (lexer->identifierEquals(FnvHash::Constants::LINES))
  {
    lexer->nextToken();
    acceptIdentifier("TERMINATED");
    accept(Token::BY);

    format->setLinesTerminatedBy(this->expr());
  }

  if (lexer->identifierEquals(FnvHash::Constants::COLLECTION))
  {
    lexer->nextToken();
    acceptIdentifier("ITEMS");
    acceptIdentifier("TERMINATED");
    accept(Token::BY);
    format->setCollectionItemsTerminatedBy(this->expr());
  }

  if (lexer->identifierEquals(FnvHash::Constants::MAP))
  {
    lexer->nextToken();
    acceptIdentifier("KEYS");
    acceptIdentifier("TERMINATED");
    accept(Token::BY);
    format->setMapKeysTerminatedBy(this->expr());
  }

  if (lexer->identifierEquals(FnvHash::Constants::SERDE))
  {
    lexer->nextToken();
    format->setSerde(this->expr());
  }

  return format;
}

SQLOver_WindowingBound_ptr SQLExprParser::parseWindowingBound()
{
  if (lexer->identifierEquals(FnvHash::Constants::PRECEDING))
  {
    lexer->nextToken();
    return SQLOver_WindowingBound::PRECEDING;
  }
  else if (lexer->identifierEquals(FnvHash::Constants::FOLLOWING))
  {
    lexer->nextToken();
    return SQLOver_WindowingBound::FOLLOWING;
  }
  else if (lexer->identifierEquals(FnvHash::Constants::CURRENT) ||
           lexer->token_->name->c_str() == Token::CURRENT.name->c_str())
  {
    lexer->nextToken();
    if (lexer->identifierEquals(FnvHash::Constants::ROW))
    {
      lexer->nextToken();
    }
    else
    {
      accept(Token::ROW);
    }
    return SQLOver_WindowingBound::CURRENT_ROW;
  }
  else if (lexer->identifierEquals(FnvHash::Constants::UNBOUNDED))
  {
    lexer->nextToken();
    if (lexer->identifierEquals(FnvHash::Constants::PRECEDING))
    {
      lexer->nextToken();
      return SQLOver_WindowingBound::UNBOUNDED_PRECEDING;
    }
    else
    {
      acceptIdentifier("FOLLOWING");
      return SQLOver_WindowingBound::UNBOUNDED_FOLLOWING;
    }
  }

  return nullptr;
}